Commit b763c011 authored by unknown's avatar unknown

merge


sql/ha_federated.cc:
  Auto merged
sql/lock.cc:
  Auto merged
sql/mysql_priv.h:
  Auto merged
sql/sp.cc:
  Auto merged
sql/sql_base.cc:
  Auto merged
sql/sql_handler.cc:
  Auto merged
sql/sql_insert.cc:
  Auto merged
sql/sql_lex.cc:
  Auto merged
sql/sql_lex.h:
  Auto merged
sql/sql_parse.cc:
  Auto merged
sql/sql_prepare.cc:
  Auto merged
sql/sql_table.cc:
  Auto merged
parents 9a7ec951 b34d5bd2
...@@ -686,7 +686,7 @@ explain extended select period_add("9602",-12),period_diff(199505,"9404"),from_d ...@@ -686,7 +686,7 @@ explain extended select period_add("9602",-12),period_diff(199505,"9404"),from_d
id select_type table type possible_keys key key_len ref rows Extra id select_type table type possible_keys key key_len ref rows Extra
1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used 1 SIMPLE NULL NULL NULL NULL NULL NULL NULL No tables used
Warnings: Warnings:
Note 1003 select sql_no_cache period_add(_latin1'9602',-(12)) AS `period_add("9602",-12)`,period_diff(199505,_latin1'9404') AS `period_diff(199505,"9404")`,from_days(to_days(_latin1'960101')) AS `from_days(to_days("960101"))`,dayofmonth(_latin1'1997-01-02') AS `dayofmonth("1997-01-02")`,month(_latin1'1997-01-02') AS `month("1997-01-02")`,monthname(_latin1'1972-03-04') AS `monthname("1972-03-04")`,dayofyear(_latin1'0000-00-00') AS `dayofyear("0000-00-00")`,hour(_latin1'1997-03-03 23:03:22') AS `HOUR("1997-03-03 23:03:22")`,minute(_latin1'23:03:22') AS `MINUTE("23:03:22")`,second(230322) AS `SECOND(230322)`,quarter(980303) AS `QUARTER(980303)`,week(_latin1'1998-03-03',0) AS `WEEK("1998-03-03")`,yearweek(_latin1'2000-01-01',1) AS `yearweek("2000-01-01",1)`,week(19950101,1) AS `week(19950101,1)`,year(_latin1'98-02-03') AS `year("98-02-03")`,(weekday(to_days(curdate())) - weekday(to_days(now()))) AS `weekday(curdate())-weekday(now())`,dayname(to_days(_latin1'1962-03-03')) AS `dayname("1962-03-03")`,unix_timestamp() AS `unix_timestamp()`,sec_to_time((time_to_sec(_latin1'0:30:47') / 6.21)) AS `sec_to_time(time_to_sec("0:30:47")/6.21)`,curtime() AS `curtime()`,utc_time() AS `utc_time()`,curdate() AS `curdate()`,utc_date() AS `utc_date()`,utc_timestamp() AS `utc_timestamp()`,date_format(_latin1'1997-01-02 03:04:05',_latin1'%M %W %D %Y %y %m %d %h %i %s %w') AS `date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w")`,from_unixtime(unix_timestamp(_latin1'1994-03-02 10:11:12')) AS `from_unixtime(unix_timestamp("1994-03-02 10:11:12"))`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `"1997-12-31 23:59:59" + INTERVAL 1 SECOND`,(_latin1'1998-01-01 00:00:00' - interval 1 second) AS `"1998-01-01 00:00:00" - INTERVAL 1 SECOND`,(_latin1'1997-12-31' + interval 1 day) AS `INTERVAL 1 DAY + "1997-12-31"`,extract(year from _latin1'1999-01-02 10:11:12') AS `extract(YEAR FROM "1999-01-02 10:11:12")`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND)` Note 1003 select sql_no_cache period_add(_latin1'9602',-(12)) AS `period_add("9602",-12)`,period_diff(199505,_latin1'9404') AS `period_diff(199505,"9404")`,from_days(to_days(_latin1'960101')) AS `from_days(to_days("960101"))`,dayofmonth(_latin1'1997-01-02') AS `dayofmonth("1997-01-02")`,month(_latin1'1997-01-02') AS `month("1997-01-02")`,monthname(_latin1'1972-03-04') AS `monthname("1972-03-04")`,dayofyear(_latin1'0000-00-00') AS `dayofyear("0000-00-00")`,hour(_latin1'1997-03-03 23:03:22') AS `HOUR("1997-03-03 23:03:22")`,minute(_latin1'23:03:22') AS `MINUTE("23:03:22")`,second(230322) AS `SECOND(230322)`,quarter(980303) AS `QUARTER(980303)`,week(_latin1'1998-03-03',0) AS `WEEK("1998-03-03")`,yearweek(_latin1'2000-01-01',1) AS `yearweek("2000-01-01",1)`,week(19950101,1) AS `week(19950101,1)`,year(_latin1'98-02-03') AS `year("98-02-03")`,(weekday(curdate()) - weekday(now())) AS `weekday(curdate())-weekday(now())`,dayname(_latin1'1962-03-03') AS `dayname("1962-03-03")`,unix_timestamp() AS `unix_timestamp()`,sec_to_time((time_to_sec(_latin1'0:30:47') / 6.21)) AS `sec_to_time(time_to_sec("0:30:47")/6.21)`,curtime() AS `curtime()`,utc_time() AS `utc_time()`,curdate() AS `curdate()`,utc_date() AS `utc_date()`,utc_timestamp() AS `utc_timestamp()`,date_format(_latin1'1997-01-02 03:04:05',_latin1'%M %W %D %Y %y %m %d %h %i %s %w') AS `date_format("1997-01-02 03:04:05", "%M %W %D %Y %y %m %d %h %i %s %w")`,from_unixtime(unix_timestamp(_latin1'1994-03-02 10:11:12')) AS `from_unixtime(unix_timestamp("1994-03-02 10:11:12"))`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `"1997-12-31 23:59:59" + INTERVAL 1 SECOND`,(_latin1'1998-01-01 00:00:00' - interval 1 second) AS `"1998-01-01 00:00:00" - INTERVAL 1 SECOND`,(_latin1'1997-12-31' + interval 1 day) AS `INTERVAL 1 DAY + "1997-12-31"`,extract(year from _latin1'1999-01-02 10:11:12') AS `extract(YEAR FROM "1999-01-02 10:11:12")`,(_latin1'1997-12-31 23:59:59' + interval 1 second) AS `date_add("1997-12-31 23:59:59",INTERVAL 1 SECOND)`
SET @TMP=NOW(); SET @TMP=NOW();
CREATE TABLE t1 (d DATETIME); CREATE TABLE t1 (d DATETIME);
INSERT INTO t1 VALUES (NOW()); INSERT INTO t1 VALUES (NOW());
......
...@@ -1072,6 +1072,188 @@ Database (mysqltest3) ...@@ -1072,6 +1072,188 @@ Database (mysqltest3)
mysqltest3 mysqltest3
-------- switch to master ------- -------- switch to master -------
######## CREATE PROCEDURE p1() READS SQL DATA SELECT "this is p1" ########
-------- switch to master -------
INSERT INTO t1 SET f1= 15 + 1;
SELECT MAX(f1) FROM t1;
MAX(f1)
16
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
15
-------- switch to master -------
CREATE PROCEDURE p1() READS SQL DATA SELECT "this is p1";
SELECT MAX(f1) FROM t1;
MAX(f1)
16
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
16
-------- switch to master -------
ROLLBACK;
SELECT MAX(f1) FROM t1;
MAX(f1)
16
TEST-INFO: MASTER: The INSERT is committed (Succeeded)
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
16
TEST-INFO: SLAVE: The INSERT is committed (Succeeded)
-------- switch to master -------
flush logs;
-------- switch to slave --------
flush logs;
-------- switch to master -------
SHOW PROCEDURE STATUS LIKE 'p1';
Db mysqltest1
Name p1
Type PROCEDURE
Definer root@localhost
Modified #
Created #
Security_type DEFINER
Comment
-------- switch to slave -------
SHOW PROCEDURE STATUS LIKE 'p1';
Db mysqltest1
Name p1
Type PROCEDURE
Definer @
Modified #
Created #
Security_type DEFINER
Comment
######## ALTER PROCEDURE p1 COMMENT "I have been altered" ########
-------- switch to master -------
INSERT INTO t1 SET f1= 16 + 1;
SELECT MAX(f1) FROM t1;
MAX(f1)
17
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
16
-------- switch to master -------
ALTER PROCEDURE p1 COMMENT "I have been altered";
SELECT MAX(f1) FROM t1;
MAX(f1)
17
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
17
-------- switch to master -------
ROLLBACK;
SELECT MAX(f1) FROM t1;
MAX(f1)
17
TEST-INFO: MASTER: The INSERT is committed (Succeeded)
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
17
TEST-INFO: SLAVE: The INSERT is committed (Succeeded)
-------- switch to master -------
flush logs;
-------- switch to slave --------
flush logs;
-------- switch to master -------
SHOW PROCEDURE STATUS LIKE 'p1';
Db mysqltest1
Name p1
Type PROCEDURE
Definer root@localhost
Modified #
Created #
Security_type DEFINER
Comment I have been altered
-------- switch to slave -------
SHOW PROCEDURE STATUS LIKE 'p1';
Db mysqltest1
Name p1
Type PROCEDURE
Definer @
Modified #
Created #
Security_type DEFINER
Comment I have been altered
######## DROP PROCEDURE p1 ########
-------- switch to master -------
INSERT INTO t1 SET f1= 17 + 1;
SELECT MAX(f1) FROM t1;
MAX(f1)
18
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
17
-------- switch to master -------
DROP PROCEDURE p1;
SELECT MAX(f1) FROM t1;
MAX(f1)
18
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
18
-------- switch to master -------
ROLLBACK;
SELECT MAX(f1) FROM t1;
MAX(f1)
18
TEST-INFO: MASTER: The INSERT is committed (Succeeded)
-------- switch to slave --------
SELECT MAX(f1) FROM t1;
MAX(f1)
18
TEST-INFO: SLAVE: The INSERT is committed (Succeeded)
-------- switch to master -------
flush logs;
-------- switch to slave --------
flush logs;
-------- switch to master -------
SHOW PROCEDURE STATUS LIKE 'p1';
-------- switch to slave -------
SHOW PROCEDURE STATUS LIKE 'p1';
DROP DATABASE IF EXISTS mysqltest1; DROP DATABASE IF EXISTS mysqltest1;
DROP DATABASE IF EXISTS mysqltest2; DROP DATABASE IF EXISTS mysqltest2;
DROP DATABASE IF EXISTS mysqltest3; DROP DATABASE IF EXISTS mysqltest3;
...@@ -43,9 +43,8 @@ drop view v1; ...@@ -43,9 +43,8 @@ drop view v1;
select * from v1 order by a; select * from v1 order by a;
ERROR 42S02: Table 'test.v1' doesn't exist ERROR 42S02: Table 'test.v1' doesn't exist
drop table t1; drop table t1;
show binlog events; show binlog events limit 1,100;
Log_name Pos Event_type Server_id End_log_pos Info Log_name Pos Event_type Server_id End_log_pos Info
slave-bin.000001 # Format_desc 2 # Server ver: 5.0.13-beta-debug-log, Binlog ver: 4
slave-bin.000001 # Query 1 # use `test`; create table t1 (a int) slave-bin.000001 # Query 1 # use `test`; create table t1 (a int)
slave-bin.000001 # Query 1 # use `test`; insert into t1 values (1) slave-bin.000001 # Query 1 # use `test`; insert into t1 values (1)
slave-bin.000001 # Query 1 # use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=root@localhost SQL SECURITY DEFINER VIEW v1 AS select a from t1 slave-bin.000001 # Query 1 # use `test`; CREATE ALGORITHM=UNDEFINED DEFINER=root@localhost SQL SECURITY DEFINER VIEW v1 AS select a from t1
......
...@@ -2205,3 +2205,46 @@ select * from (select f1 as f2 from v1) v where v.f2='a'; ...@@ -2205,3 +2205,46 @@ select * from (select f1 as f2 from v1) v where v.f2='a';
f2 f2
drop view v1; drop view v1;
drop table t1; drop table t1;
CREATE TABLE t1 (date DATE NOT NULL);
INSERT INTO t1 VALUES ('2005-09-06');
CREATE VIEW v1 AS SELECT DAYNAME(date) FROM t1;
SHOW CREATE VIEW v1;
View Create View
v1 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select dayname(`t1`.`date`) AS `DAYNAME(date)` from `t1`
CREATE VIEW v2 AS SELECT DAYOFWEEK(date) FROM t1;
SHOW CREATE VIEW v2;
View Create View
v2 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v2` AS select dayofweek(`t1`.`date`) AS `DAYOFWEEK(date)` from `t1`
CREATE VIEW v3 AS SELECT WEEKDAY(date) FROM t1;
SHOW CREATE VIEW v3;
View Create View
v3 CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v3` AS select weekday(`t1`.`date`) AS `WEEKDAY(date)` from `t1`
SELECT DAYNAME('2005-09-06');
DAYNAME('2005-09-06')
Tuesday
SELECT DAYNAME(date) FROM t1;
DAYNAME(date)
Tuesday
SELECT * FROM v1;
DAYNAME(date)
Tuesday
SELECT DAYOFWEEK('2005-09-06');
DAYOFWEEK('2005-09-06')
3
SELECT DAYOFWEEK(date) FROM t1;
DAYOFWEEK(date)
3
SELECT * FROM v2;
DAYOFWEEK(date)
3
SELECT WEEKDAY('2005-09-06');
WEEKDAY('2005-09-06')
1
SELECT WEEKDAY(date) FROM t1;
WEEKDAY(date)
1
SELECT * FROM v3;
WEEKDAY(date)
1
DROP TABLE t1;
DROP VIEW v1, v2, v3;
...@@ -340,6 +340,57 @@ connection master; ...@@ -340,6 +340,57 @@ connection master;
SELECT '-------- switch to master -------' as ""; SELECT '-------- switch to master -------' as "";
--enable_query_log --enable_query_log
# End of 4.1 tests
###############################################################
# Cases with stored procedures
###############################################################
let $my_stmt= CREATE PROCEDURE p1() READS SQL DATA SELECT "this is p1";
let $my_master_commit= true;
let $my_slave_commit= true;
--source include/rpl_stmt_seq.inc
--vertical_results
--replace_column 5 # 6 #
SHOW PROCEDURE STATUS LIKE 'p1';
--disable_query_log
SELECT '-------- switch to slave -------' as "";
--enable_query_log
connection slave;
--replace_column 5 # 6 #
SHOW PROCEDURE STATUS LIKE 'p1';
connection master;
--horizontal_results
let $my_stmt= ALTER PROCEDURE p1 COMMENT "I have been altered";
let $my_master_commit= true;
let $my_slave_commit= true;
--source include/rpl_stmt_seq.inc
--vertical_results
--replace_column 5 # 6 #
SHOW PROCEDURE STATUS LIKE 'p1';
--disable_query_log
SELECT '-------- switch to slave -------' as "";
--enable_query_log
connection slave;
--replace_column 5 # 6 #
SHOW PROCEDURE STATUS LIKE 'p1';
connection master;
--horizontal_results
let $my_stmt= DROP PROCEDURE p1;
let $my_master_commit= true;
let $my_slave_commit= true;
--source include/rpl_stmt_seq.inc
--vertical_results
SHOW PROCEDURE STATUS LIKE 'p1';
--disable_query_log
SELECT '-------- switch to slave -------' as "";
--enable_query_log
connection slave;
SHOW PROCEDURE STATUS LIKE 'p1';
connection master;
--horizontal_results
############################################################### ###############################################################
# Cleanup # Cleanup
############################################################### ###############################################################
...@@ -349,4 +400,4 @@ DROP DATABASE IF EXISTS mysqltest2; ...@@ -349,4 +400,4 @@ DROP DATABASE IF EXISTS mysqltest2;
DROP DATABASE IF EXISTS mysqltest3; DROP DATABASE IF EXISTS mysqltest3;
--enable_warnings --enable_warnings
# End of 4.1 tests
...@@ -44,4 +44,4 @@ connection master; ...@@ -44,4 +44,4 @@ connection master;
drop table t1; drop table t1;
sync_slave_with_master; sync_slave_with_master;
--replace_column 2 # 5 # --replace_column 2 # 5 #
show binlog events; show binlog events limit 1,100;
...@@ -10,6 +10,11 @@ drop function if exists f1; ...@@ -10,6 +10,11 @@ drop function if exists f1;
drop procedure if exists p1; drop procedure if exists p1;
--enable_warnings --enable_warnings
# Create additional connections used through test
connect (addconroot1, localhost, root,,);
connect (addconroot2, localhost, root,,);
connection default;
create table t1 (i int); create table t1 (i int);
# let us test some very simple trigger # let us test some very simple trigger
...@@ -680,12 +685,10 @@ end| ...@@ -680,12 +685,10 @@ end|
delimiter ;| delimiter ;|
update t1 set data = 1; update t1 set data = 1;
connect (addconroot, localhost, root,,); connection addconroot1;
connection addconroot;
update t1 set data = 2; update t1 set data = 2;
connection default; connection default;
disconnect addconroot;
drop table t1; drop table t1;
# #
...@@ -765,3 +768,110 @@ insert into t1 values (3); ...@@ -765,3 +768,110 @@ insert into t1 values (3);
select * from t1; select * from t1;
drop trigger t1_bi; drop trigger t1_bi;
drop tables t1, t2; drop tables t1, t2;
# Tests for bug #12704 "Server crashes during trigger execution".
# If we run DML statements and CREATE TRIGGER statements concurrently
# it may happen that trigger will be created while DML statement is
# waiting for table lock. In this case we have to reopen tables and
# recalculate prelocking set.
# Unfortunately these tests rely on the order in which tables are locked
# by statement so they are non determenistic and are disabled.
--disable_parsing
create table t1 (id int);
create table t2 (id int);
create table t3 (id int);
create function f1() returns int return (select max(id)+2 from t2);
create view v1 as select f1() as f;
# Let us check that we notice trigger at all
connection addconroot1;
lock tables t2 write;
connection default;
send insert into t1 values ((select max(id) from t2)), (2);
--sleep 1
connection addconroot2;
create trigger t1_trg before insert on t1 for each row set NEW.id:= 1;
connection addconroot1;
unlock tables;
connection default;
reap;
select * from t1;
# Check that we properly calculate new prelocking set
insert into t2 values (3);
connection addconroot1;
lock tables t2 write;
connection default;
send insert into t1 values ((select max(id) from t2)), (4);
--sleep 1
connection addconroot2;
drop trigger t1_trg;
create trigger t1_trg before insert on t1 for each row
insert into t3 values (new.id);
connection addconroot1;
unlock tables;
connection default;
reap;
select * from t1;
select * from t3;
# We should be able to do this even if fancy views are involved
connection addconroot1;
lock tables t2 write;
connection default;
send insert into t1 values ((select max(f) from v1)), (6);
--sleep 1
connection addconroot2;
drop trigger t1_trg;
create trigger t1_trg before insert on t1 for each row
insert into t3 values (new.id + 100);
connection addconroot1;
unlock tables;
connection default;
reap;
select * from t1;
select * from t3;
# This also should work for multi-update
# Let us drop trigger to demonstrate that prelocking set is really
# rebuilt
drop trigger t1_trg;
connection addconroot1;
lock tables t2 write;
connection default;
send update t1, t2 set t1.id=10 where t1.id=t2.id;
--sleep 1
connection addconroot2;
create trigger t1_trg before update on t1 for each row
insert into t3 values (new.id);
connection addconroot1;
unlock tables;
connection default;
reap;
select * from t1;
select * from t3;
# And even for multi-update converted from ordinary update thanks to view
drop view v1;
drop trigger t1_trg;
create view v1 as select t1.id as id1 from t1, t2 where t1.id= t2.id;
insert into t2 values (10);
connection addconroot1;
lock tables t2 write;
connection default;
send update v1 set id1= 11;
--sleep 1
connection addconroot2;
create trigger t1_trg before update on t1 for each row
insert into t3 values (new.id + 100);
connection addconroot1;
unlock tables;
connection default;
reap;
select * from t1;
select * from t3;
drop function f1;
drop view v1;
drop table t1, t2, t3;
--enable_parsing
...@@ -2086,3 +2086,34 @@ create view v1 as select * from t1; ...@@ -2086,3 +2086,34 @@ create view v1 as select * from t1;
select * from (select f1 as f2 from v1) v where v.f2='a'; select * from (select f1 as f2 from v1) v where v.f2='a';
drop view v1; drop view v1;
drop table t1; drop table t1;
#
# Bugs #12963, #13000: wrong creation of VIEW with DAYNAME, DAYOFWEEK, and WEEKDAY
#
CREATE TABLE t1 (date DATE NOT NULL);
INSERT INTO t1 VALUES ('2005-09-06');
CREATE VIEW v1 AS SELECT DAYNAME(date) FROM t1;
SHOW CREATE VIEW v1;
CREATE VIEW v2 AS SELECT DAYOFWEEK(date) FROM t1;
SHOW CREATE VIEW v2;
CREATE VIEW v3 AS SELECT WEEKDAY(date) FROM t1;
SHOW CREATE VIEW v3;
SELECT DAYNAME('2005-09-06');
SELECT DAYNAME(date) FROM t1;
SELECT * FROM v1;
SELECT DAYOFWEEK('2005-09-06');
SELECT DAYOFWEEK(date) FROM t1;
SELECT * FROM v2;
SELECT WEEKDAY('2005-09-06');
SELECT WEEKDAY(date) FROM t1;
SELECT * FROM v3;
DROP TABLE t1;
DROP VIEW v1, v2, v3;
...@@ -522,7 +522,8 @@ static int check_foreign_data_source( ...@@ -522,7 +522,8 @@ static int check_foreign_data_source(
static int parse_url_error(FEDERATED_SHARE *share, TABLE *table, int error_num) static int parse_url_error(FEDERATED_SHARE *share, TABLE *table, int error_num)
{ {
char buf[table->s->connect_string.length+1]; char buf[FEDERATED_QUERY_BUFFER_SIZE];
int buf_len;
DBUG_ENTER("ha_federated parse_url_error"); DBUG_ENTER("ha_federated parse_url_error");
if (share->scheme) if (share->scheme)
{ {
...@@ -532,9 +533,11 @@ static int parse_url_error(FEDERATED_SHARE *share, TABLE *table, int error_num) ...@@ -532,9 +533,11 @@ static int parse_url_error(FEDERATED_SHARE *share, TABLE *table, int error_num)
my_free((gptr) share->scheme, MYF(0)); my_free((gptr) share->scheme, MYF(0));
share->scheme= 0; share->scheme= 0;
} }
buf_len= (table->s->connect_string.length > (FEDERATED_QUERY_BUFFER_SIZE - 1))
strnmov(buf, table->s->connect_string.str, table->s->connect_string.length+1); ? FEDERATED_QUERY_BUFFER_SIZE - 1 : table->s->connect_string.length;
buf[table->s->connect_string.length]= '\0';
strnmov(buf, table->s->connect_string.str, buf_len);
buf[buf_len]= '\0';
my_error(error_num, MYF(0), buf); my_error(error_num, MYF(0), buf);
DBUG_RETURN(error_num); DBUG_RETURN(error_num);
} }
...@@ -743,13 +746,12 @@ ha_federated::ha_federated(TABLE *table_arg) ...@@ -743,13 +746,12 @@ ha_federated::ha_federated(TABLE *table_arg)
uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row) uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row)
{ {
uint num_fields;
ulong *lengths; ulong *lengths;
Field **field; Field **field;
DBUG_ENTER("ha_federated::convert_row_to_internal_format"); DBUG_ENTER("ha_federated::convert_row_to_internal_format");
num_fields= mysql_num_fields(stored_result); // num_fields= mysql_num_fields(stored_result);
lengths= mysql_fetch_lengths(stored_result); lengths= mysql_fetch_lengths(stored_result);
memset(record, 0, table->s->null_bytes); memset(record, 0, table->s->null_bytes);
...@@ -1115,12 +1117,9 @@ bool ha_federated::create_where_from_key(String *to, ...@@ -1115,12 +1117,9 @@ bool ha_federated::create_where_from_key(String *to,
for (int i= 0; i <= 1; i++) for (int i= 0; i <= 1; i++)
{ {
bool needs_quotes; bool needs_quotes;
uint loop_counter= 0;
KEY_PART_INFO *key_part; KEY_PART_INFO *key_part;
if (ranges[i] == NULL) if (ranges[i] == NULL)
continue; continue;
const byte *key= ranges[i]->key;
uint key_length= ranges[i]->length;
if (both_not_null) if (both_not_null)
{ {
...@@ -1435,7 +1434,6 @@ const char **ha_federated::bas_ext() const ...@@ -1435,7 +1434,6 @@ const char **ha_federated::bas_ext() const
int ha_federated::open(const char *name, int mode, uint test_if_locked) int ha_federated::open(const char *name, int mode, uint test_if_locked)
{ {
int rc;
DBUG_ENTER("ha_federated::open"); DBUG_ENTER("ha_federated::open");
if (!(share= get_share(name, table))) if (!(share= get_share(name, table)))
...@@ -1753,7 +1751,6 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) ...@@ -1753,7 +1751,6 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
/* /*
buffers for following strings buffers for following strings
*/ */
char error_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char old_field_value_buffer[STRING_BUFFER_USUAL_SIZE]; char old_field_value_buffer[STRING_BUFFER_USUAL_SIZE];
char new_field_value_buffer[STRING_BUFFER_USUAL_SIZE]; char new_field_value_buffer[STRING_BUFFER_USUAL_SIZE];
char update_buffer[FEDERATED_QUERY_BUFFER_SIZE]; char update_buffer[FEDERATED_QUERY_BUFFER_SIZE];
...@@ -1823,10 +1820,8 @@ int ha_federated::update_row(const byte *old_data, byte *new_data) ...@@ -1823,10 +1820,8 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
where_string.append(FEDERATED_ISNULL); where_string.append(FEDERATED_ISNULL);
else else
{ {
uint o_len;
(*field)->val_str(&old_field_value, (*field)->val_str(&old_field_value,
(char*) (old_data + (*field)->offset())); (char*) (old_data + (*field)->offset()));
o_len= (*field)->pack_length();
(*field)->quote_data(&old_field_value); (*field)->quote_data(&old_field_value);
where_string.append(old_field_value); where_string.append(old_field_value);
} }
...@@ -1964,8 +1959,6 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key, ...@@ -1964,8 +1959,6 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
int retval; int retval;
char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; char error_buffer[FEDERATED_QUERY_BUFFER_SIZE];
char index_value[STRING_BUFFER_USUAL_SIZE]; char index_value[STRING_BUFFER_USUAL_SIZE];
char key_value[STRING_BUFFER_USUAL_SIZE];
char test_value[STRING_BUFFER_USUAL_SIZE];
char sql_query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; char sql_query_buffer[FEDERATED_QUERY_BUFFER_SIZE];
String index_string(index_value, String index_string(index_value,
sizeof(index_value), sizeof(index_value),
...@@ -2046,7 +2039,6 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key, ...@@ -2046,7 +2039,6 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
/* Initialized at each key walk (called multiple times unlike rnd_init()) */ /* Initialized at each key walk (called multiple times unlike rnd_init()) */
int ha_federated::index_init(uint keynr, bool sorted) int ha_federated::index_init(uint keynr, bool sorted)
{ {
int error;
DBUG_ENTER("ha_federated::index_init"); DBUG_ENTER("ha_federated::index_init");
DBUG_PRINT("info", DBUG_PRINT("info",
("table: '%s' key: %d", table->s->table_name, keynr)); ("table: '%s' key: %d", table->s->table_name, keynr));
...@@ -2153,10 +2145,6 @@ int ha_federated::index_next(byte *buf) ...@@ -2153,10 +2145,6 @@ int ha_federated::index_next(byte *buf)
int ha_federated::rnd_init(bool scan) int ha_federated::rnd_init(bool scan)
{ {
int num_fields, rows;
int retval;
char error_buffer[FEDERATED_QUERY_BUFFER_SIZE];
DBUG_ENTER("ha_federated::rnd_init"); DBUG_ENTER("ha_federated::rnd_init");
/* /*
The use of the 'scan' flag is incredibly important for this handler The use of the 'scan' flag is incredibly important for this handler
...@@ -2447,7 +2435,6 @@ void ha_federated::info(uint flag) ...@@ -2447,7 +2435,6 @@ void ha_federated::info(uint flag)
} }
if (flag & HA_STATUS_CONST) if (flag & HA_STATUS_CONST)
{ {
TABLE_SHARE *share= table->s;
block_size= 4096; block_size= 4096;
} }
} }
......
...@@ -109,7 +109,7 @@ Item *create_func_dayofmonth(Item* a) ...@@ -109,7 +109,7 @@ Item *create_func_dayofmonth(Item* a)
Item *create_func_dayofweek(Item* a) Item *create_func_dayofweek(Item* a)
{ {
return new Item_func_weekday(new Item_func_to_days(a),1); return new Item_func_weekday(a, 1);
} }
Item *create_func_dayofyear(Item* a) Item *create_func_dayofyear(Item* a)
...@@ -119,7 +119,7 @@ Item *create_func_dayofyear(Item* a) ...@@ -119,7 +119,7 @@ Item *create_func_dayofyear(Item* a)
Item *create_func_dayname(Item* a) Item *create_func_dayname(Item* a)
{ {
return new Item_func_dayname(new Item_func_to_days(a)); return new Item_func_dayname(a);
} }
Item *create_func_degrees(Item *a) Item *create_func_degrees(Item *a)
...@@ -443,7 +443,7 @@ Item *create_func_version(void) ...@@ -443,7 +443,7 @@ Item *create_func_version(void)
Item *create_func_weekday(Item* a) Item *create_func_weekday(Item* a)
{ {
return new Item_func_weekday(new Item_func_to_days(a),0); return new Item_func_weekday(a, 0);
} }
Item *create_func_year(Item* a) Item *create_func_year(Item* a)
......
...@@ -1030,16 +1030,17 @@ longlong Item_func_yearweek::val_int() ...@@ -1030,16 +1030,17 @@ longlong Item_func_yearweek::val_int()
} }
/* weekday() has a automatic to_days() on item */
longlong Item_func_weekday::val_int() longlong Item_func_weekday::val_int()
{ {
DBUG_ASSERT(fixed == 1); DBUG_ASSERT(fixed == 1);
ulong tmp_value=(ulong) args[0]->val_int(); TIME ltime;
if ((null_value=(args[0]->null_value || !tmp_value)))
return 0; /* purecov: inspected */ if (get_arg0_date(&ltime, TIME_NO_ZERO_DATE))
return 0;
return (longlong) calc_weekday(tmp_value,odbc_type)+test(odbc_type); return (longlong) calc_weekday(calc_daynr(ltime.year, ltime.month,
ltime.day),
odbc_type) + test(odbc_type);
} }
......
...@@ -257,7 +257,10 @@ class Item_func_weekday :public Item_func ...@@ -257,7 +257,10 @@ class Item_func_weekday :public Item_func
str->set(val_int(), &my_charset_bin); str->set(val_int(), &my_charset_bin);
return null_value ? 0 : str; return null_value ? 0 : str;
} }
const char *func_name() const { return "weekday"; } const char *func_name() const
{
return (odbc_type ? "dayofweek" : "weekday");
}
enum Item_result result_type () const { return INT_RESULT; } enum Item_result result_type () const { return INT_RESULT; }
void fix_length_and_dec() void fix_length_and_dec()
{ {
......
...@@ -93,23 +93,33 @@ static void print_lock_error(int error, const char *); ...@@ -93,23 +93,33 @@ static void print_lock_error(int error, const char *);
flags Options: flags Options:
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables. 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 RETURN
A lock structure pointer on success. A lock structure pointer on success.
NULL on error. 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[]= static int thr_lock_errno_to_mysql[]=
{ 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK }; { 0, 1, ER_LOCK_WAIT_TIMEOUT, ER_LOCK_DEADLOCK };
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
uint flags, bool *need_reopen)
{ {
MYSQL_LOCK *sql_lock; MYSQL_LOCK *sql_lock;
TABLE *write_lock_used; TABLE *write_lock_used;
int rc; int rc;
/* Map the return value of thr_lock to an error from errmsg.txt */
DBUG_ENTER("mysql_lock_tables"); DBUG_ENTER("mysql_lock_tables");
*need_reopen= FALSE;
for (;;) for (;;)
{ {
if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used))) if (!(sql_lock = get_lock_data(thd,tables,count, 0,&write_lock_used)))
...@@ -178,6 +188,11 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags) ...@@ -178,6 +188,11 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count, uint flags)
thd->locked=0; thd->locked=0;
retry: retry:
sql_lock=0; sql_lock=0;
if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN)
{
*need_reopen= TRUE;
break;
}
if (wait_for_tables(thd)) if (wait_for_tables(thd))
break; // Couldn't open tables break; // Couldn't open tables
} }
......
...@@ -979,7 +979,7 @@ int open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags); ...@@ -979,7 +979,7 @@ int open_tables(THD *thd, TABLE_LIST **tables, uint *counter, uint flags);
int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables); int simple_open_n_lock_tables(THD *thd,TABLE_LIST *tables);
bool open_and_lock_tables(THD *thd,TABLE_LIST *tables); bool open_and_lock_tables(THD *thd,TABLE_LIST *tables);
bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags); bool open_normal_and_derived_tables(THD *thd, TABLE_LIST *tables, uint flags);
int lock_tables(THD *thd, TABLE_LIST *tables, uint counter); int lock_tables(THD *thd, TABLE_LIST *tables, uint counter, bool *need_reopen);
TABLE *open_temporary_table(THD *thd, const char *path, const char *db, TABLE *open_temporary_table(THD *thd, const char *path, const char *db,
const char *table_name, bool link_in_list); const char *table_name, bool link_in_list);
bool rm_temporary_table(enum db_type base, char *path); bool rm_temporary_table(enum db_type base, char *path);
...@@ -987,6 +987,7 @@ void free_io_cache(TABLE *entry); ...@@ -987,6 +987,7 @@ void free_io_cache(TABLE *entry);
void intern_close_table(TABLE *entry); void intern_close_table(TABLE *entry);
bool close_thread_table(THD *thd, TABLE **table_ptr); bool close_thread_table(THD *thd, TABLE **table_ptr);
void close_temporary_tables(THD *thd); void close_temporary_tables(THD *thd);
void close_tables_for_reopen(THD *thd, TABLE_LIST *tables);
TABLE_LIST *find_table_in_list(TABLE_LIST *table, TABLE_LIST *find_table_in_list(TABLE_LIST *table,
uint offset_to_list, uint offset_to_list,
const char *db_name, const char *db_name,
...@@ -1266,10 +1267,12 @@ extern pthread_t signal_thread; ...@@ -1266,10 +1267,12 @@ extern pthread_t signal_thread;
extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd; extern struct st_VioSSLAcceptorFd * ssl_acceptor_fd;
#endif /* HAVE_OPENSSL */ #endif /* HAVE_OPENSSL */
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count, uint flags); MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count,
uint flags, bool *need_reopen);
/* mysql_lock_tables() flags bits */ /* mysql_lock_tables() flags bits */
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001 #define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
#define MYSQL_LOCK_IGNORE_FLUSH 0x0002 #define MYSQL_LOCK_IGNORE_FLUSH 0x0002
#define MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN 0x0004
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock); void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
......
...@@ -107,7 +107,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) ...@@ -107,7 +107,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
{ {
TABLE_LIST tables; TABLE_LIST tables;
TABLE *table; TABLE *table;
bool refresh; bool not_used;
DBUG_ENTER("open_proc_table"); DBUG_ENTER("open_proc_table");
/* /*
...@@ -122,7 +122,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) ...@@ -122,7 +122,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
bzero((char*) &tables, sizeof(tables)); bzero((char*) &tables, sizeof(tables));
tables.db= (char*) "mysql"; tables.db= (char*) "mysql";
tables.table_name= tables.alias= (char*)"proc"; tables.table_name= tables.alias= (char*)"proc";
if (!(table= open_table(thd, &tables, thd->mem_root, &refresh, if (!(table= open_table(thd, &tables, thd->mem_root, &not_used,
MYSQL_LOCK_IGNORE_FLUSH))) MYSQL_LOCK_IGNORE_FLUSH)))
{ {
thd->restore_backup_open_tables_state(backup); thd->restore_backup_open_tables_state(backup);
...@@ -138,7 +138,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup) ...@@ -138,7 +138,7 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
could lead to a deadlock if we have other tables opened. could lead to a deadlock if we have other tables opened.
*/ */
if (!(thd->lock= mysql_lock_tables(thd, &table, 1, if (!(thd->lock= mysql_lock_tables(thd, &table, 1,
MYSQL_LOCK_IGNORE_FLUSH))) MYSQL_LOCK_IGNORE_FLUSH, &not_used)))
{ {
close_proc_table(thd, backup); close_proc_table(thd, backup);
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -1265,7 +1265,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena, ...@@ -1265,7 +1265,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
/* /*
Add routine to the set of stored routines used by statement. Add routine which is explicitly used by statement to the set of stored
routines used by this statement.
SYNOPSIS SYNOPSIS
sp_add_used_routine() sp_add_used_routine()
...@@ -1276,7 +1277,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena, ...@@ -1276,7 +1277,8 @@ static bool add_used_routine(LEX *lex, Query_arena *arena,
rt_type - routine type (one of TYPE_ENUM_PROCEDURE/...) rt_type - routine type (one of TYPE_ENUM_PROCEDURE/...)
NOTES NOTES
Will also add element to end of 'LEX::sroutines_list' list. Will also add element to end of 'LEX::sroutines_list' list (and will
take into account that this is explicitly used routine).
To be friendly towards prepared statements one should pass To be friendly towards prepared statements one should pass
persistent arena as second argument. persistent arena as second argument.
...@@ -1287,6 +1289,37 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena, ...@@ -1287,6 +1289,37 @@ void sp_add_used_routine(LEX *lex, Query_arena *arena,
{ {
rt->set_routine_type(rt_type); rt->set_routine_type(rt_type);
(void)add_used_routine(lex, arena, &rt->m_sroutines_key); (void)add_used_routine(lex, arena, &rt->m_sroutines_key);
lex->sroutines_list_own_last= lex->sroutines_list.next;
lex->sroutines_list_own_elements= lex->sroutines_list.elements;
}
/*
Remove routines which are only indirectly used by statement from
the set of routines used by this statement.
SYNOPSIS
sp_remove_not_own_routines()
lex LEX representing statement
*/
void sp_remove_not_own_routines(LEX *lex)
{
Sroutine_hash_entry *not_own_rt, *next_rt;
for (not_own_rt= *(Sroutine_hash_entry **)lex->sroutines_list_own_last;
not_own_rt; not_own_rt= next_rt)
{
/*
It is safe to obtain not_own_rt->next after calling hash_delete() now
but we want to be more future-proof.
*/
next_rt= not_own_rt->next;
hash_delete(&lex->sroutines, (byte *)not_own_rt);
}
*(Sroutine_hash_entry **)lex->sroutines_list_own_last= NULL;
lex->sroutines_list.next= lex->sroutines_list_own_last;
lex->sroutines_list.elements= lex->sroutines_list_own_elements;
} }
...@@ -1343,6 +1376,28 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src) ...@@ -1343,6 +1376,28 @@ static void sp_update_stmt_used_routines(THD *thd, LEX *lex, HASH *src)
} }
/*
Add contents of list representing set of routines to the set of
routines used by statement.
SYNOPSIS
sp_update_stmt_used_routines()
thd Thread context
lex LEX representing statement
src List representing set from which routines will be added
NOTE
It will also add elements to end of 'LEX::sroutines_list' list.
*/
static void sp_update_stmt_used_routines(THD *thd, LEX *lex, SQL_LIST *src)
{
for (Sroutine_hash_entry *rt= (Sroutine_hash_entry *)src->first;
rt; rt= rt->next)
(void)add_used_routine(lex, thd->stmt_arena, &rt->key);
}
/* /*
Cache sub-set of routines used by statement, add tables used by these Cache sub-set of routines used by statement, add tables used by these
routines to statement table list. Do the same for all routines used routines to statement table list. Do the same for all routines used
...@@ -1463,7 +1518,7 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex) ...@@ -1463,7 +1518,7 @@ sp_cache_routines_and_add_tables_for_view(THD *thd, LEX *lex, LEX *aux_lex)
{ {
Sroutine_hash_entry **last_cached_routine_ptr= Sroutine_hash_entry **last_cached_routine_ptr=
(Sroutine_hash_entry **)lex->sroutines_list.next; (Sroutine_hash_entry **)lex->sroutines_list.next;
sp_update_stmt_used_routines(thd, lex, &aux_lex->sroutines); sp_update_stmt_used_routines(thd, lex, &aux_lex->sroutines_list);
(void)sp_cache_routines_and_add_tables_aux(thd, lex, (void)sp_cache_routines_and_add_tables_aux(thd, lex,
*last_cached_routine_ptr, FALSE); *last_cached_routine_ptr, FALSE);
} }
......
...@@ -84,6 +84,7 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking, ...@@ -84,6 +84,7 @@ void sp_get_prelocking_info(THD *thd, bool *need_prelocking,
bool *first_no_prelocking); bool *first_no_prelocking);
void sp_add_used_routine(LEX *lex, Query_arena *arena, void sp_add_used_routine(LEX *lex, Query_arena *arena,
sp_name *rt, char rt_type); sp_name *rt, char rt_type);
void sp_remove_not_own_routines(LEX *lex);
void sp_update_sp_used_routines(HASH *dst, HASH *src); void sp_update_sp_used_routines(HASH *dst, HASH *src);
bool sp_cache_routines_and_add_tables(THD *thd, LEX *lex, bool sp_cache_routines_and_add_tables(THD *thd, LEX *lex,
bool first_no_prelock); bool first_no_prelock);
......
...@@ -1909,10 +1909,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, ...@@ -1909,10 +1909,6 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
attached it above in this function). attached it above in this function).
Now we'll save the 'tail', and detach it. Now we'll save the 'tail', and detach it.
*/ */
DBUG_ASSERT(!lex_query_tables_own_last ||
lex_query_tables_own_last == m_lex->query_tables_own_last &&
prelocking_tables == *(m_lex->query_tables_own_last));
lex_query_tables_own_last= m_lex->query_tables_own_last; lex_query_tables_own_last= m_lex->query_tables_own_last;
prelocking_tables= *lex_query_tables_own_last; prelocking_tables= *lex_query_tables_own_last;
*lex_query_tables_own_last= NULL; *lex_query_tables_own_last= NULL;
......
...@@ -1399,7 +1399,6 @@ bool reopen_table(TABLE *table,bool locked) ...@@ -1399,7 +1399,6 @@ bool reopen_table(TABLE *table,bool locked)
tmp.status= table->status; tmp.status= table->status;
tmp.keys_in_use_for_query= tmp.s->keys_in_use; tmp.keys_in_use_for_query= tmp.s->keys_in_use;
tmp.used_keys= tmp.s->keys_for_keyread; tmp.used_keys= tmp.s->keys_for_keyread;
tmp.force_index= tmp.force_index;
/* Get state */ /* Get state */
tmp.s->key_length= table->s->key_length; tmp.s->key_length= table->s->key_length;
...@@ -1430,6 +1429,9 @@ bool reopen_table(TABLE *table,bool locked) ...@@ -1430,6 +1429,9 @@ bool reopen_table(TABLE *table,bool locked)
for (key=0 ; key < table->s->keys ; key++) for (key=0 ; key < table->s->keys ; key++)
for (part=0 ; part < table->key_info[key].usable_key_parts ; part++) for (part=0 ; part < table->key_info[key].usable_key_parts ; part++)
table->key_info[key].key_part[part].field->table= table; table->key_info[key].key_part[part].field->table= table;
if (table->triggers)
table->triggers->set_table(table);
VOID(pthread_cond_broadcast(&COND_refresh)); VOID(pthread_cond_broadcast(&COND_refresh));
error=0; error=0;
...@@ -1478,7 +1480,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) ...@@ -1478,7 +1480,7 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
TABLE *table,*next,**prev; TABLE *table,*next,**prev;
TABLE **tables,**tables_ptr; // For locks TABLE **tables,**tables_ptr; // For locks
bool error=0; bool error=0, not_used;
if (get_locks) if (get_locks)
{ {
/* The ptr is checked later */ /* The ptr is checked later */
...@@ -1519,7 +1521,8 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh) ...@@ -1519,7 +1521,8 @@ bool reopen_tables(THD *thd,bool get_locks,bool in_refresh)
MYSQL_LOCK *lock; MYSQL_LOCK *lock;
/* We should always get these locks */ /* We should always get these locks */
thd->some_tables_deleted=0; thd->some_tables_deleted=0;
if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr - tables), 0))) if ((lock= mysql_lock_tables(thd, tables, (uint) (tables_ptr - tables),
0, &not_used)))
{ {
thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock); thd->locked_tables=mysql_lock_merge(thd->locked_tables,lock);
} }
...@@ -1969,9 +1972,15 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) ...@@ -1969,9 +1972,15 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
/* /*
Ignore placeholders for derived tables. After derived tables Ignore placeholders for derived tables. After derived tables
processing, link to created temporary table will be put here. processing, link to created temporary table will be put here.
If this is derived table for view then we still want to process
routines used by this view.
*/ */
if (tables->derived) if (tables->derived)
{
if (tables->view)
goto process_view_routines;
continue; continue;
}
if (tables->schema_table) if (tables->schema_table)
{ {
if (!mysql_schema_table(thd, thd->lex, tables)) if (!mysql_schema_table(thd, thd->lex, tables))
...@@ -2003,23 +2012,12 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) ...@@ -2003,23 +2012,12 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
if (query_tables_last_own == &(tables->next_global) && if (query_tables_last_own == &(tables->next_global) &&
tables->view->query_tables) tables->view->query_tables)
query_tables_last_own= tables->view->query_tables_last; query_tables_last_own= tables->view->query_tables_last;
/* /*
Again if needed we have to get cache all routines used by this view Let us free memory used by 'sroutines' hash here since we never
and add tables used by them to table list. call destructor for this LEX.
*/ */
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
tables->view->sroutines.records)
{
/* We have at least one table in TL here */
if (!query_tables_last_own)
query_tables_last_own= thd->lex->query_tables_last;
sp_cache_routines_and_add_tables_for_view(thd, thd->lex,
tables->view);
}
/* Cleanup hashes because destructo for this LEX is never called */
hash_free(&tables->view->sroutines); hash_free(&tables->view->sroutines);
continue; goto process_view_routines;
} }
if (refresh) // Refresh in progress if (refresh) // Refresh in progress
...@@ -2031,11 +2029,6 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) ...@@ -2031,11 +2029,6 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
thd->version=refresh_version; thd->version=refresh_version;
TABLE **prev_table= &thd->open_tables; TABLE **prev_table= &thd->open_tables;
bool found=0; bool found=0;
/*
QQ: What we should do if we have started building of table list
for prelocking ??? Probably throw it away ? But before we should
mark all temporary tables as free? How about locked ?
*/
for (TABLE_LIST *tmp= *start; tmp; tmp= tmp->next_global) for (TABLE_LIST *tmp= *start; tmp; tmp= tmp->next_global)
{ {
/* Close normal (not temporary) changed tables */ /* Close normal (not temporary) changed tables */
...@@ -2059,6 +2052,18 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) ...@@ -2059,6 +2052,18 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
pthread_mutex_unlock(&LOCK_open); pthread_mutex_unlock(&LOCK_open);
if (found) if (found)
VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh VOID(pthread_cond_broadcast(&COND_refresh)); // Signal to refresh
/*
Let us prepare for recalculation of set of prelocked tables.
First we pretend that we have finished calculation which we
were doing currently. Then we restore list of tables to be
opened and set of used routines to the state in which they were
before first open_tables() call for this statement (i.e. before
we have calculated current set of tables for prelocking).
*/
if (query_tables_last_own)
thd->lex->mark_as_requiring_prelocking(query_tables_last_own);
thd->lex->chop_off_not_own_tables();
sp_remove_not_own_routines(thd->lex);
goto restart; goto restart;
} }
result= -1; // Fatal error result= -1; // Fatal error
...@@ -2089,6 +2094,21 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) ...@@ -2089,6 +2094,21 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables) if (tables->lock_type != TL_UNLOCK && ! thd->locked_tables)
tables->table->reginfo.lock_type=tables->lock_type; tables->table->reginfo.lock_type=tables->lock_type;
tables->table->grant= tables->grant; tables->table->grant= tables->grant;
process_view_routines:
/*
Again we may need cache all routines used by this view and add
tables used by them to table list.
*/
if (tables->view && !thd->prelocked_mode &&
!thd->lex->requires_prelocking() &&
tables->view->sroutines_list.elements)
{
/* We have at least one table in TL here. */
if (!query_tables_last_own)
query_tables_last_own= thd->lex->query_tables_last;
sp_cache_routines_and_add_tables_for_view(thd, thd->lex, tables->view);
}
} }
thd->proc_info=0; thd->proc_info=0;
free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block free_root(&new_frm_mem, MYF(0)); // Free pre-alloced block
...@@ -2193,7 +2213,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) ...@@ -2193,7 +2213,8 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
{ {
DBUG_ASSERT(thd->lock == 0); // You must lock everything at once DBUG_ASSERT(thd->lock == 0); // You must lock everything at once
if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK) if ((table->reginfo.lock_type= lock_type) != TL_UNLOCK)
if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1, 0))) if (! (thd->lock= mysql_lock_tables(thd, &table_list->table, 1, 0,
&refresh)))
table= 0; table= 0;
} }
} }
...@@ -2221,11 +2242,20 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type) ...@@ -2221,11 +2242,20 @@ TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type lock_type)
int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables)
{ {
DBUG_ENTER("simple_open_n_lock_tables");
uint counter; uint counter;
if (open_tables(thd, &tables, &counter, 0) || bool need_reopen;
lock_tables(thd, tables, counter)) DBUG_ENTER("simple_open_n_lock_tables");
DBUG_RETURN(-1); /* purecov: inspected */
for ( ; ; )
{
if (open_tables(thd, &tables, &counter, 0))
DBUG_RETURN(-1);
if (!lock_tables(thd, tables, counter, &need_reopen))
break;
if (!need_reopen)
DBUG_RETURN(-1);
close_tables_for_reopen(thd, tables);
}
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -2250,10 +2280,20 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables) ...@@ -2250,10 +2280,20 @@ int simple_open_n_lock_tables(THD *thd, TABLE_LIST *tables)
bool open_and_lock_tables(THD *thd, TABLE_LIST *tables) bool open_and_lock_tables(THD *thd, TABLE_LIST *tables)
{ {
uint counter; uint counter;
bool need_reopen;
DBUG_ENTER("open_and_lock_tables"); DBUG_ENTER("open_and_lock_tables");
if (open_tables(thd, &tables, &counter, 0) ||
lock_tables(thd, tables, counter) || for ( ; ; )
mysql_handle_derived(thd->lex, &mysql_derived_prepare) || {
if (open_tables(thd, &tables, &counter, 0))
DBUG_RETURN(-1);
if (!lock_tables(thd, tables, counter, &need_reopen))
break;
if (!need_reopen)
DBUG_RETURN(-1);
close_tables_for_reopen(thd, tables);
}
if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
(thd->fill_derived_tables() && (thd->fill_derived_tables() &&
mysql_handle_derived(thd->lex, &mysql_derived_filling))) mysql_handle_derived(thd->lex, &mysql_derived_filling)))
DBUG_RETURN(TRUE); /* purecov: inspected */ DBUG_RETURN(TRUE); /* purecov: inspected */
...@@ -2321,7 +2361,12 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table) ...@@ -2321,7 +2361,12 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
lock_tables() lock_tables()
thd Thread handler thd Thread handler
tables Tables to lock tables Tables to lock
count umber of opened tables count Number of opened tables
need_reopen Out parameter which if TRUE indicates that some
tables were dropped or altered during this call
and therefore invoker should reopen tables and
try to lock them once again (in this case
lock_tables() will also return error).
NOTES NOTES
You can't call lock_tables twice, as this would break the dead-lock-free You can't call lock_tables twice, as this would break the dead-lock-free
...@@ -2337,7 +2382,7 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table) ...@@ -2337,7 +2382,7 @@ static void mark_real_tables_as_free_for_reuse(TABLE_LIST *table)
-1 Error -1 Error
*/ */
int lock_tables(THD *thd, TABLE_LIST *tables, uint count) int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
{ {
TABLE_LIST *table; TABLE_LIST *table;
...@@ -2353,6 +2398,8 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count) ...@@ -2353,6 +2398,8 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
*/ */
DBUG_ASSERT(!thd->lex->requires_prelocking() || tables); DBUG_ASSERT(!thd->lex->requires_prelocking() || tables);
*need_reopen= FALSE;
if (!tables) if (!tables)
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -2385,7 +2432,9 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count) ...@@ -2385,7 +2432,9 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
thd->options|= OPTION_TABLE_LOCK; thd->options|= OPTION_TABLE_LOCK;
} }
if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start), 0))) if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start),
MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN,
need_reopen)))
{ {
if (thd->lex->requires_prelocking()) if (thd->lex->requires_prelocking())
{ {
...@@ -2464,6 +2513,28 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count) ...@@ -2464,6 +2513,28 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count)
} }
/*
Prepare statement for reopening of tables and recalculation of set of
prelocked tables.
SYNOPSIS
close_tables_for_reopen()
thd Thread context
tables List of tables which we were trying to open and lock
*/
void close_tables_for_reopen(THD *thd, TABLE_LIST *tables)
{
thd->lex->chop_off_not_own_tables();
sp_remove_not_own_routines(thd->lex);
for (TABLE_LIST *tmp= tables; tmp; tmp= tmp->next_global)
if (tmp->table && !tmp->table->s->tmp_table)
tmp->table= 0;
close_thread_tables(thd);
}
/* /*
Open a single table without table caching and don't set it in open_list Open a single table without table caching and don't set it in open_list
Used by alter_table to open a temporary table and when creating Used by alter_table to open a temporary table and when creating
......
...@@ -346,6 +346,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, ...@@ -346,6 +346,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
uint num_rows; uint num_rows;
byte *key; byte *key;
uint key_len; uint key_len;
bool not_used;
DBUG_ENTER("mysql_ha_read"); DBUG_ENTER("mysql_ha_read");
DBUG_PRINT("enter",("'%s'.'%s' as '%s'", DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
tables->db, tables->table_name, tables->alias)); tables->db, tables->table_name, tables->alias));
...@@ -431,7 +432,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables, ...@@ -431,7 +432,7 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF); protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
HANDLER_TABLES_HACK(thd); HANDLER_TABLES_HACK(thd);
lock= mysql_lock_tables(thd, &tables->table, 1, 0); lock= mysql_lock_tables(thd, &tables->table, 1, 0, &not_used);
HANDLER_TABLES_HACK(thd); HANDLER_TABLES_HACK(thd);
if (!lock) if (!lock)
......
...@@ -1839,6 +1839,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) ...@@ -1839,6 +1839,7 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
if (di->tables_in_use && ! thd->lock) if (di->tables_in_use && ! thd->lock)
{ {
bool not_used;
/* /*
Request for new delayed insert. Request for new delayed insert.
Lock the table, but avoid to be blocked by a global read lock. Lock the table, but avoid to be blocked by a global read lock.
...@@ -1850,7 +1851,8 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg) ...@@ -1850,7 +1851,8 @@ extern "C" pthread_handler_decl(handle_delayed_insert,arg)
inserts are done. inserts are done.
*/ */
if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1, if (! (thd->lock= mysql_lock_tables(thd, &di->table, 1,
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))) MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK,
&not_used)))
{ {
/* Fatal error */ /* Fatal error */
di->dead= 1; di->dead= 1;
......
...@@ -180,6 +180,8 @@ void lex_start(THD *thd, uchar *buf,uint length) ...@@ -180,6 +180,8 @@ void lex_start(THD *thd, uchar *buf,uint length)
if (lex->sroutines.records) if (lex->sroutines.records)
my_hash_reset(&lex->sroutines); my_hash_reset(&lex->sroutines);
lex->sroutines_list.empty(); lex->sroutines_list.empty();
lex->sroutines_list_own_last= lex->sroutines_list.next;
lex->sroutines_list_own_elements= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1614,6 +1616,8 @@ st_lex::st_lex() ...@@ -1614,6 +1616,8 @@ st_lex::st_lex()
{ {
hash_init(&sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0); hash_init(&sroutines, system_charset_info, 0, 0, 0, sp_sroutine_key, 0, 0);
sroutines_list.empty(); sroutines_list.empty();
sroutines_list_own_last= sroutines_list.next;
sroutines_list_own_elements= 0;
} }
...@@ -2026,6 +2030,8 @@ void st_lex::cleanup_after_one_table_open() ...@@ -2026,6 +2030,8 @@ void st_lex::cleanup_after_one_table_open()
if (sroutines.records) if (sroutines.records)
my_hash_reset(&sroutines); my_hash_reset(&sroutines);
sroutines_list.empty(); sroutines_list.empty();
sroutines_list_own_last= sroutines_list.next;
sroutines_list_own_elements= 0;
} }
......
...@@ -861,8 +861,15 @@ typedef struct st_lex ...@@ -861,8 +861,15 @@ typedef struct st_lex
/* /*
List linking elements of 'sroutines' set. Allows you to add new elements List linking elements of 'sroutines' set. Allows you to add new elements
to this set as you iterate through the list of existing elements. to this set as you iterate through the list of existing elements.
'sroutines_list_own_last' is pointer to ::next member of last element of
this list which represents routine which is explicitly used by query.
'sroutines_list_own_elements' number of explicitly used routines.
We use these two members for restoring of 'sroutines_list' to the state
in which it was right after query parsing.
*/ */
SQL_LIST sroutines_list; SQL_LIST sroutines_list;
byte **sroutines_list_own_last;
uint sroutines_list_own_elements;
st_sp_chistics sp_chistics; st_sp_chistics sp_chistics;
bool only_view; /* used for SHOW CREATE TABLE/VIEW */ bool only_view; /* used for SHOW CREATE TABLE/VIEW */
...@@ -978,6 +985,15 @@ typedef struct st_lex ...@@ -978,6 +985,15 @@ typedef struct st_lex
{ {
return ( query_tables_own_last ? *query_tables_own_last : 0); return ( query_tables_own_last ? *query_tables_own_last : 0);
} }
void chop_off_not_own_tables()
{
if (query_tables_own_last)
{
*query_tables_own_last= 0;
query_tables_last= query_tables_own_last;
query_tables_own_last= 0;
}
}
void cleanup_after_one_table_open(); void cleanup_after_one_table_open();
void push_context(Name_resolution_context *context) void push_context(Name_resolution_context *context)
......
...@@ -4033,6 +4033,9 @@ mysql_execute_command(THD *thd) ...@@ -4033,6 +4033,9 @@ mysql_execute_command(THD *thd)
goto error; goto error;
} }
if (end_active_trans(thd))
goto error;
if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0]) if (!lex->sphead->m_db.str || !lex->sphead->m_db.str[0])
{ {
lex->sphead->m_db.length= strlen(thd->db); lex->sphead->m_db.length= strlen(thd->db);
...@@ -4287,6 +4290,9 @@ mysql_execute_command(THD *thd) ...@@ -4287,6 +4290,9 @@ mysql_execute_command(THD *thd)
sp->m_name.str, sp->m_name.str,
lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0)) lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
goto error; goto error;
if (end_active_trans(thd))
goto error;
memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics)); memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
if (!trust_routine_creators && mysql_bin_log.is_open() && if (!trust_routine_creators && mysql_bin_log.is_open() &&
!sp->m_chistics->detistic && !sp->m_chistics->detistic &&
...@@ -4346,6 +4352,9 @@ mysql_execute_command(THD *thd) ...@@ -4346,6 +4352,9 @@ mysql_execute_command(THD *thd)
if (check_routine_access(thd, ALTER_PROC_ACL, db, name, if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
lex->sql_command == SQLCOM_DROP_PROCEDURE, 0)) lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
goto error; goto error;
if (end_active_trans(thd))
goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (sp_automatic_privileges && !opt_noacl && if (sp_automatic_privileges && !opt_noacl &&
sp_revoke_privileges(thd, db, name, sp_revoke_privileges(thd, db, name,
......
...@@ -1103,30 +1103,39 @@ static int mysql_test_update(Prepared_statement *stmt, ...@@ -1103,30 +1103,39 @@ static int mysql_test_update(Prepared_statement *stmt,
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
uint want_privilege; uint want_privilege;
#endif #endif
bool need_reopen;
DBUG_ENTER("mysql_test_update"); DBUG_ENTER("mysql_test_update");
if (update_precheck(thd, table_list)) if (update_precheck(thd, table_list))
goto error; goto error;
if (open_tables(thd, &table_list, &table_count, 0)) for ( ; ; )
goto error;
if (table_list->multitable_view)
{ {
DBUG_ASSERT(table_list->view != 0); if (open_tables(thd, &table_list, &table_count, 0))
DBUG_PRINT("info", ("Switch to multi-update")); goto error;
/* pass counter value */
thd->lex->table_count= table_count; if (table_list->multitable_view)
/* convert to multiupdate */ {
DBUG_RETURN(2); DBUG_ASSERT(table_list->view != 0);
DBUG_PRINT("info", ("Switch to multi-update"));
/* pass counter value */
thd->lex->table_count= table_count;
/* convert to multiupdate */
DBUG_RETURN(2);
}
if (!lock_tables(thd, table_list, table_count, &need_reopen))
break;
if (!need_reopen)
goto error;
close_tables_for_reopen(thd, table_list);
} }
/* /*
thd->fill_derived_tables() is false here for sure (because it is thd->fill_derived_tables() is false here for sure (because it is
preparation of PS, so we even do not check it). preparation of PS, so we even do not check it).
*/ */
if (lock_tables(thd, table_list, table_count) || if (mysql_handle_derived(thd->lex, &mysql_derived_prepare))
mysql_handle_derived(thd->lex, &mysql_derived_prepare))
goto error; goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
......
...@@ -1850,6 +1850,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, ...@@ -1850,6 +1850,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
List_iterator_fast<Item> it(*items); List_iterator_fast<Item> it(*items);
Item *item; Item *item;
Field *tmp_field; Field *tmp_field;
bool not_used;
DBUG_ENTER("create_table_from_items"); DBUG_ENTER("create_table_from_items");
tmp_table.alias= 0; tmp_table.alias= 0;
...@@ -1908,8 +1909,15 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info, ...@@ -1908,8 +1909,15 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/*
FIXME: What happens if trigger manages to be created while we are
obtaining this lock ? May be it is sensible just to disable
trigger execution in this case ? Or will MYSQL_LOCK_IGNORE_FLUSH
save us from that ?
*/
table->reginfo.lock_type=TL_WRITE; table->reginfo.lock_type=TL_WRITE;
if (! ((*lock)= mysql_lock_tables(thd, &table, 1, MYSQL_LOCK_IGNORE_FLUSH))) if (! ((*lock)= mysql_lock_tables(thd, &table, 1,
MYSQL_LOCK_IGNORE_FLUSH, &not_used)))
{ {
VOID(pthread_mutex_lock(&LOCK_open)); VOID(pthread_mutex_lock(&LOCK_open));
hash_delete(&open_cache,(byte*) table); hash_delete(&open_cache,(byte*) table);
......
...@@ -510,6 +510,25 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table) ...@@ -510,6 +510,25 @@ bool Table_triggers_list::prepare_record1_accessors(TABLE *table)
} }
/*
Adjust Table_triggers_list with new TABLE pointer.
SYNOPSIS
set_table()
new_table - new pointer to TABLE instance
*/
void Table_triggers_list::set_table(TABLE *new_table)
{
table= new_table;
for (Field **field= table->triggers->record1_field ; *field ; field++)
{
(*field)->table= (*field)->orig_table= new_table;
(*field)->table_name= &new_table->alias;
}
}
/* /*
Check whenever .TRG file for table exist and load all triggers it contains. Check whenever .TRG file for table exist and load all triggers it contains.
......
...@@ -98,6 +98,8 @@ class Table_triggers_list: public Sql_alloc ...@@ -98,6 +98,8 @@ class Table_triggers_list: public Sql_alloc
return test(bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]); return test(bodies[TRG_EVENT_UPDATE][TRG_ACTION_BEFORE]);
} }
void set_table(TABLE *new_table);
friend class Item_trigger_field; friend class Item_trigger_field;
friend void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex, friend void sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
Table_triggers_list *triggers); Table_triggers_list *triggers);
......
...@@ -134,25 +134,33 @@ int mysql_update(THD *thd, ...@@ -134,25 +134,33 @@ int mysql_update(THD *thd,
SQL_SELECT *select; SQL_SELECT *select;
READ_RECORD info; READ_RECORD info;
SELECT_LEX *select_lex= &thd->lex->select_lex; SELECT_LEX *select_lex= &thd->lex->select_lex;
bool need_reopen;
DBUG_ENTER("mysql_update"); DBUG_ENTER("mysql_update");
LINT_INIT(timestamp_query_id); LINT_INIT(timestamp_query_id);
if (open_tables(thd, &table_list, &table_count, 0)) for ( ; ; )
DBUG_RETURN(1);
if (table_list->multitable_view)
{ {
DBUG_ASSERT(table_list->view != 0); if (open_tables(thd, &table_list, &table_count, 0))
DBUG_PRINT("info", ("Switch to multi-update")); DBUG_RETURN(1);
/* pass counter value */
thd->lex->table_count= table_count; if (table_list->multitable_view)
/* convert to multiupdate */ {
DBUG_RETURN(2); DBUG_ASSERT(table_list->view != 0);
DBUG_PRINT("info", ("Switch to multi-update"));
/* pass counter value */
thd->lex->table_count= table_count;
/* convert to multiupdate */
DBUG_RETURN(2);
}
if (!lock_tables(thd, table_list, table_count, &need_reopen))
break;
if (!need_reopen)
DBUG_RETURN(1);
close_tables_for_reopen(thd, table_list);
} }
if (lock_tables(thd, table_list, table_count) || if (mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
mysql_handle_derived(thd->lex, &mysql_derived_prepare) ||
(thd->fill_derived_tables() && (thd->fill_derived_tables() &&
mysql_handle_derived(thd->lex, &mysql_derived_filling))) mysql_handle_derived(thd->lex, &mysql_derived_filling)))
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -721,7 +729,6 @@ static table_map get_table_map(List<Item> *items) ...@@ -721,7 +729,6 @@ static table_map get_table_map(List<Item> *items)
bool mysql_multi_update_prepare(THD *thd) bool mysql_multi_update_prepare(THD *thd)
{ {
LEX *lex= thd->lex; LEX *lex= thd->lex;
ulong opened_tables;
TABLE_LIST *table_list= lex->query_tables; TABLE_LIST *table_list= lex->query_tables;
TABLE_LIST *tl, *leaves; TABLE_LIST *tl, *leaves;
List<Item> *fields= &lex->select_lex.item_list; List<Item> *fields= &lex->select_lex.item_list;
...@@ -735,13 +742,16 @@ bool mysql_multi_update_prepare(THD *thd) ...@@ -735,13 +742,16 @@ bool mysql_multi_update_prepare(THD *thd)
uint table_count= lex->table_count; uint table_count= lex->table_count;
const bool using_lock_tables= thd->locked_tables != 0; const bool using_lock_tables= thd->locked_tables != 0;
bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI); bool original_multiupdate= (thd->lex->sql_command == SQLCOM_UPDATE_MULTI);
bool need_reopen= FALSE;
DBUG_ENTER("mysql_multi_update_prepare"); DBUG_ENTER("mysql_multi_update_prepare");
/* following need for prepared statements, to run next time multi-update */ /* following need for prepared statements, to run next time multi-update */
thd->lex->sql_command= SQLCOM_UPDATE_MULTI; thd->lex->sql_command= SQLCOM_UPDATE_MULTI;
reopen_tables:
/* open tables and create derived ones, but do not lock and fill them */ /* open tables and create derived ones, but do not lock and fill them */
if ((original_multiupdate && if (((original_multiupdate || need_reopen) &&
open_tables(thd, &table_list, &table_count, 0)) || open_tables(thd, &table_list, &table_count, 0)) ||
mysql_handle_derived(lex, &mysql_derived_prepare)) mysql_handle_derived(lex, &mysql_derived_prepare))
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
...@@ -847,20 +857,17 @@ bool mysql_multi_update_prepare(THD *thd) ...@@ -847,20 +857,17 @@ bool mysql_multi_update_prepare(THD *thd)
} }
} }
opened_tables= thd->status_var.opened_tables;
/* now lock and fill tables */ /* now lock and fill tables */
if (lock_tables(thd, table_list, table_count)) if (lock_tables(thd, table_list, table_count, &need_reopen))
DBUG_RETURN(TRUE);
/*
we have to re-call fixfields for fixed items, because lock maybe
reopened tables
*/
if (opened_tables != thd->status_var.opened_tables)
{ {
if (!need_reopen)
DBUG_RETURN(TRUE);
/* /*
Fields items cleanup(). There are only Item_fields in the list, so we We have to reopen tables since some of them were altered or dropped
do not do Item tree walking during lock_tables() or something was done with their triggers.
Let us do some cleanups to be able do setup_table() and setup_fields()
once again.
*/ */
List_iterator_fast<Item> it(*fields); List_iterator_fast<Item> it(*fields);
Item *item; Item *item;
...@@ -871,12 +878,8 @@ bool mysql_multi_update_prepare(THD *thd) ...@@ -871,12 +878,8 @@ bool mysql_multi_update_prepare(THD *thd)
for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global) for (TABLE_LIST *tbl= table_list; tbl; tbl= tbl->next_global)
tbl->cleanup_items(); tbl->cleanup_items();
if (setup_tables(thd, &lex->select_lex.context, close_tables_for_reopen(thd, table_list);
&lex->select_lex.top_join_list, goto reopen_tables;
table_list, &lex->select_lex.where,
&lex->select_lex.leaf_tables, FALSE) ||
setup_fields_with_no_wrap(thd, 0, *fields, 2, 0, 0))
DBUG_RETURN(TRUE);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment