diff --git a/mysql-test/r/federated_server.result b/mysql-test/r/federated_server.result index 7a1a6e0970d45cdb509aa0a4d9e52d2741c494e4..a3e7cd793a67e76c2726faa7573c40303c5d9497 100644 --- a/mysql-test/r/federated_server.result +++ b/mysql-test/r/federated_server.result @@ -20,6 +20,14 @@ CREATE TABLE first_db.t1 ( `name` varchar(64) NOT NULL default '' ) DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS first_db.t2; +Warnings: +Note 1051 Unknown table 't2' +CREATE TABLE first_db.t2 ( +`id` int(20) NOT NULL, +`name` varchar(64) NOT NULL default '' + ) +DEFAULT CHARSET=latin1; use second_db; DROP TABLE IF EXISTS second_db.t1; Warnings: @@ -29,6 +37,14 @@ CREATE TABLE second_db.t1 ( `name` varchar(64) NOT NULL default '' ) DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS second_db.t2; +Warnings: +Note 1051 Unknown table 't2' +CREATE TABLE second_db.t2 ( +`id` int(20) NOT NULL, +`name` varchar(64) NOT NULL default '' + ) +DEFAULT CHARSET=latin1; drop server if exists 'server_one'; create server 'server_one' foreign data wrapper 'mysql' options (HOST '127.0.0.1', @@ -60,10 +76,10 @@ CREATE TABLE federated.old ( ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/first_db/t1'; -INSERT INTO federated.old (id, name) values (1, 'federated.old url'); +INSERT INTO federated.old (id, name) values (1, 'federated.old-> first_db.t1, url format'); SELECT * FROM federated.old; id name -1 federated.old url +1 federated.old-> first_db.t1, url format DROP TABLE IF EXISTS federated.old2; Warnings: Note 1051 Unknown table 'old2' @@ -72,8 +88,37 @@ CREATE TABLE federated.old2 ( `name` varchar(64) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/first_db/t2'; +INSERT INTO federated.old2 (id, name) values (1, 'federated.old2-> first_db.t2, url format'); +SELECT * FROM federated.old2; +id name +1 federated.old2-> first_db.t2, url format +DROP TABLE IF EXISTS federated.urldb2t1; +Warnings: +Note 1051 Unknown table 'urldb2t1' +CREATE TABLE federated.urldb2t1 ( +`id` int(20) NOT NULL, +`name` varchar(64) NOT NULL default '' + ) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/second_db/t1'; -INSERT INTO federated.old2 (id, name) values (1, 'federated.old2 url'); +INSERT INTO federated.urldb2t1 (id, name) values (1, 'federated.urldb2t1 -> second_db.t1, url format'); +SELECT * FROM federated.urldb2t1; +id name +1 federated.urldb2t1 -> second_db.t1, url format +DROP TABLE IF EXISTS federated.urldb2t2; +Warnings: +Note 1051 Unknown table 'urldb2t2' +CREATE TABLE federated.urldb2t2 ( +`id` int(20) NOT NULL, +`name` varchar(64) NOT NULL default '' + ) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/second_db/t2'; +INSERT INTO federated.urldb2t2 (id, name) values (1, 'federated.urldb2t2 -> second_db.t2, url format'); +SELECT * FROM federated.urldb2t2; +id name +1 federated.urldb2t2 -> second_db.t2, url format DROP TABLE IF EXISTS federated.t1; Warnings: Note 1051 Unknown table 't1' @@ -83,18 +128,38 @@ CREATE TABLE federated.t1 ( ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 CONNECTION='server_one'; -INSERT INTO federated.t1 (id, name) values (1, 'server_one, new scheme'); +INSERT INTO federated.t1 (id, name) values (1, 'server_one, new scheme, first_db.t1'); SELECT * FROM federated.t1; id name -1 federated.old url -1 server_one, new scheme +1 federated.old-> first_db.t1, url format +1 server_one, new scheme, first_db.t1 +DROP TABLE IF EXISTS federated.whatever; +Warnings: +Note 1051 Unknown table 'whatever' +CREATE TABLE federated.whatever ( +`id` int(20) NOT NULL, +`name` varchar(64) NOT NULL default '' + ) +ENGINE="FEDERATED" DEFAULT CHARSET=latin1 +CONNECTION='server_one/t1'; +INSERT INTO federated.whatever (id, name) values (1, 'server_one, new scheme, whatever, first_db.t1'); +SELECT * FROM federated.whatever; +id name +1 federated.old-> first_db.t1, url format +1 server_one, new scheme, first_db.t1 +1 server_one, new scheme, whatever, first_db.t1 ALTER SERVER 'server_one' options(DATABASE 'second_db'); -flush tables; -INSERT INTO federated.t1 (id, name) values (1, 'server_two, new scheme'); +INSERT INTO federated.t1 (id, name) values (1, 'server_two, new scheme, second_db.t1'); SELECT * FROM federated.t1; id name -1 federated.old2 url -1 server_two, new scheme +1 federated.urldb2t1 -> second_db.t1, url format +1 server_two, new scheme, second_db.t1 +INSERT INTO federated.whatever (id, name) values (1, 'server_two, new scheme, whatever, second_db.t1'); +SELECT * FROM federated.whatever; +id name +1 federated.urldb2t1 -> second_db.t1, url format +1 server_two, new scheme, second_db.t1 +1 server_two, new scheme, whatever, second_db.t1 drop table federated.t1; drop server 'server_one'; drop server 'server_two'; @@ -104,6 +169,116 @@ drop table first_db.t1; drop table second_db.t1; drop database first_db; drop database second_db; +create database db_legitimate; +create database db_bogus; +use db_legitimate; +CREATE TABLE db_legitimate.t1 ( +`id` int(20) NOT NULL, +`name` varchar(64) NOT NULL default '' + ); +INSERT INTO db_legitimate.t1 VALUES ('1','this is legitimate'); +use db_bogus; +CREATE TABLE db_bogus.t1 ( +`id` int(20) NOT NULL, +`name` varchar(64) NOT NULL default '' + ) +; +INSERT INTO db_bogus.t1 VALUES ('2','this is bogus'); +create server 's1' foreign data wrapper 'mysql' options +(HOST '127.0.0.1', +DATABASE 'db_legitimate', +USER 'root', +PASSWORD '', +PORT SLAVE_PORT, +SOCKET '', +OWNER 'root'); +create user guest_select@localhost; +grant select on federated.* to guest_select@localhost; +create user guest_super@localhost; +grant select,SUPER,RELOAD on *.* to guest_super@localhost; +create user guest_usage@localhost; +grant usage on *.* to guest_usage@localhost; +CREATE TABLE federated.t1 ( +`id` int(20) NOT NULL, +`name` varchar(64) NOT NULL default '' + ) ENGINE = FEDERATED CONNECTION = 's1'; +select * from federated.t1; +id name +1 this is legitimate +alter server s1 options (database 'db_bogus'); +ERROR 42000: Access denied; you need the SUPER privilege for this operation +flush tables; +select * from federated.t1; +id name +1 this is legitimate +alter server s1 options (database 'db_bogus'); +ERROR 42000: Access denied; you need the SUPER privilege for this operation +flush tables; +select * from federated.t1; +id name +1 this is legitimate +alter server s1 options (database 'db_bogus'); +flush tables; +select * from federated.t1; +id name +2 this is bogus +drop server if exists 's1'; +ERROR 42000: Access denied; you need the SUPER privilege for this operation +create server 's1' foreign data wrapper 'mysql' options +(HOST '127.0.0.1', +DATABASE 'db_legitimate', +USER 'root', +PASSWORD '', +PORT SLAVE_PORT, +SOCKET '', +OWNER 'root'); +ERROR 42000: Access denied; you need the SUPER privilege for this operation +drop server 's1'; +create server 's1' foreign data wrapper 'mysql' options +(HOST '127.0.0.1', +DATABASE 'db_legitimate', +USER 'root', +PASSWORD '', +PORT SLAVE_PORT, +SOCKET '', +OWNER 'root'); +flush tables; +select * from federated.t1; +id name +1 this is legitimate +drop database db_legitimate; +drop database db_bogus; +drop user guest_super@localhost; +drop user guest_usage@localhost; +drop user guest_select@localhost; +drop table federated.t1; +drop server 's1'; +# End of 5.1 tests +use test; +create procedure p1 () +begin +DECLARE v INT DEFAULT 0; +DECLARE e INT DEFAULT 0; +DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET e = e + 1; +WHILE v < 10000 do +CREATE SERVER s +FOREIGN DATA WRAPPER mysql +OPTIONS (USER 'Remote', HOST '192.168.1.106', DATABASE 'test'); +ALTER SERVER s OPTIONS (USER 'Remote'); +DROP SERVER s; +SET v = v + 1; +END WHILE; +SELECT e > 0; +END// +use test; +call p1(); +call p1(); +e > 0 +1 +e > 0 +1 +drop procedure p1; +drop server if exists s; DROP TABLE IF EXISTS federated.t1; DROP DATABASE IF EXISTS federated; DROP TABLE IF EXISTS federated.t1; diff --git a/mysql-test/r/heap_btree.result b/mysql-test/r/heap_btree.result index fd789a39d88a3de2cf82cda06106d7cb5a13d6b5..ab4b892170a59173689efb40efda246dcc1967a9 100644 --- a/mysql-test/r/heap_btree.result +++ b/mysql-test/r/heap_btree.result @@ -280,6 +280,33 @@ a 1 1 drop table t1; +CREATE TABLE t1 ( +c1 CHAR(3), +c2 INTEGER, +KEY USING BTREE(c1), +KEY USING BTREE(c2) +) ENGINE= MEMORY; +INSERT INTO t1 VALUES ('ABC',0), ('A',0), ('B',0), ('C',0); +UPDATE t1 SET c2= c2 + 1 WHERE c1 = 'A'; +SELECT * FROM t1; +c1 c2 +ABC 0 +A 1 +B 0 +C 0 +DROP TABLE t1; +CREATE TABLE t1 ( +c1 ENUM('1', '2'), +UNIQUE USING BTREE(c1) +) ENGINE= MEMORY DEFAULT CHARSET= utf8; +INSERT INTO t1 VALUES('1'), ('2'); +DROP TABLE t1; +CREATE TABLE t1 ( +c1 SET('1', '2'), +UNIQUE USING BTREE(c1) +) ENGINE= MEMORY DEFAULT CHARSET= utf8; +INSERT INTO t1 VALUES('1'), ('2'); +DROP TABLE t1; End of 4.1 tests CREATE TABLE t1(val INT, KEY USING BTREE(val)) ENGINE=memory; INSERT INTO t1 VALUES(0); diff --git a/mysql-test/r/myisam.result b/mysql-test/r/myisam.result index bb666b2e499f0fc5b97caf31fae731263bc761ff..dcb471510cd751b02da165c3fcc26b9727ba6e54 100644 --- a/mysql-test/r/myisam.result +++ b/mysql-test/r/myisam.result @@ -943,6 +943,156 @@ SHOW TABLE STATUS LIKE 't1'; Name Engine Version Row_format Rows Avg_row_length Data_length Max_data_length Index_length Data_free Auto_increment Create_time Update_time Check_time Collation Checksum Create_options Comment t1 MyISAM 10 Dynamic X X X 72057594037927935 X X X X X X latin1_swedish_ci X max_rows=4100100100 avg_row_length=70100 DROP TABLE t1; +CREATE TABLE t1 (c1 TEXT NOT NULL, KEY c1 (c1(10))) ENGINE=MyISAM; +INSERT INTO t1 VALUES +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), +(''), (''), (''), (''), +(' B'), (' B'), (' B'), (' B'); +SELECT DISTINCT COUNT(*) FROM t1 WHERE c1 = ''; +COUNT(*) +4 +SELECT DISTINCT length(c1), c1 FROM t1 WHERE c1 = ''; +length(c1) c1 +0 +SELECT DISTINCT COUNT(*) FROM t1 IGNORE INDEX (c1) WHERE c1 = ''; +COUNT(*) +4 +SELECT DISTINCT length(c1), c1 FROM t1 IGNORE INDEX (c1) WHERE c1 = ''; +length(c1) c1 +0 +SELECT DISTINCT length(c1), c1 FROM t1 ORDER BY c1; +length(c1) c1 +0 +2 A +2 B +DROP TABLE t1; End of 4.1 tests set storage_engine=MyISAM; drop table if exists t1,t2,t3; diff --git a/mysql-test/t/federated_server.test b/mysql-test/t/federated_server.test index 3e47d9bc95d45221442523028c863ec6070dd04b..b2075b8e262b565676c7505c03f03c13a25bce5a 100644 --- a/mysql-test/t/federated_server.test +++ b/mysql-test/t/federated_server.test @@ -17,6 +17,13 @@ CREATE TABLE first_db.t1 ( ) DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS first_db.t2; +CREATE TABLE first_db.t2 ( + `id` int(20) NOT NULL, + `name` varchar(64) NOT NULL default '' + ) + DEFAULT CHARSET=latin1; + use second_db; DROP TABLE IF EXISTS second_db.t1; CREATE TABLE second_db.t1 ( @@ -25,6 +32,13 @@ CREATE TABLE second_db.t1 ( ) DEFAULT CHARSET=latin1; +DROP TABLE IF EXISTS second_db.t2; +CREATE TABLE second_db.t2 ( + `id` int(20) NOT NULL, + `name` varchar(64) NOT NULL default '' + ) + DEFAULT CHARSET=latin1; + connection master; drop server if exists 'server_one'; @@ -61,7 +75,7 @@ eval CREATE TABLE federated.old ( ENGINE="FEDERATED" DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/first_db/t1'; -INSERT INTO federated.old (id, name) values (1, 'federated.old url'); +INSERT INTO federated.old (id, name) values (1, 'federated.old-> first_db.t1, url format'); SELECT * FROM federated.old; @@ -72,9 +86,32 @@ eval CREATE TABLE federated.old2 ( `name` varchar(64) NOT NULL default '' ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/first_db/t2'; + +INSERT INTO federated.old2 (id, name) values (1, 'federated.old2-> first_db.t2, url format'); +SELECT * FROM federated.old2; + +DROP TABLE IF EXISTS federated.urldb2t1; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.urldb2t1 ( + `id` int(20) NOT NULL, + `name` varchar(64) NOT NULL default '' + ) + ENGINE="FEDERATED" DEFAULT CHARSET=latin1 CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/second_db/t1'; +INSERT INTO federated.urldb2t1 (id, name) values (1, 'federated.urldb2t1 -> second_db.t1, url format'); +SELECT * FROM federated.urldb2t1; -INSERT INTO federated.old2 (id, name) values (1, 'federated.old2 url'); +DROP TABLE IF EXISTS federated.urldb2t2; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval CREATE TABLE federated.urldb2t2 ( + `id` int(20) NOT NULL, + `name` varchar(64) NOT NULL default '' + ) + ENGINE="FEDERATED" DEFAULT CHARSET=latin1 + CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/second_db/t2'; +INSERT INTO federated.urldb2t2 (id, name) values (1, 'federated.urldb2t2 -> second_db.t2, url format'); +SELECT * FROM federated.urldb2t2; DROP TABLE IF EXISTS federated.t1; CREATE TABLE federated.t1 ( @@ -84,17 +121,30 @@ CREATE TABLE federated.t1 ( ENGINE="FEDERATED" DEFAULT CHARSET=latin1 CONNECTION='server_one'; -INSERT INTO federated.t1 (id, name) values (1, 'server_one, new scheme'); +INSERT INTO federated.t1 (id, name) values (1, 'server_one, new scheme, first_db.t1'); SELECT * FROM federated.t1; +DROP TABLE IF EXISTS federated.whatever; +CREATE TABLE federated.whatever ( + `id` int(20) NOT NULL, + `name` varchar(64) NOT NULL default '' + ) + ENGINE="FEDERATED" DEFAULT CHARSET=latin1 + CONNECTION='server_one/t1'; +INSERT INTO federated.whatever (id, name) values (1, 'server_one, new scheme, whatever, first_db.t1'); +SELECT * FROM federated.whatever; + ALTER SERVER 'server_one' options(DATABASE 'second_db'); -flush tables; +# FLUSH TABLES is now unneccessary -INSERT INTO federated.t1 (id, name) values (1, 'server_two, new scheme'); +INSERT INTO federated.t1 (id, name) values (1, 'server_two, new scheme, second_db.t1'); SELECT * FROM federated.t1; +INSERT INTO federated.whatever (id, name) values (1, 'server_two, new scheme, whatever, second_db.t1'); +SELECT * FROM federated.whatever; + drop table federated.t1; drop server 'server_one'; @@ -107,4 +157,166 @@ drop table second_db.t1; drop database first_db; drop database second_db; +# +# Bug#25671 - CREATE/DROP/ALTER SERVER should require privileges +# +# Changes to SERVER declarations should require SUPER privilege. +# Based upon test case by Giuseppe Maxia + +create database db_legitimate; +create database db_bogus; + +use db_legitimate; +CREATE TABLE db_legitimate.t1 ( + `id` int(20) NOT NULL, + `name` varchar(64) NOT NULL default '' + ); +INSERT INTO db_legitimate.t1 VALUES ('1','this is legitimate'); + +use db_bogus; +CREATE TABLE db_bogus.t1 ( + `id` int(20) NOT NULL, + `name` varchar(64) NOT NULL default '' + ) + ; +INSERT INTO db_bogus.t1 VALUES ('2','this is bogus'); + +connection master; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval create server 's1' foreign data wrapper 'mysql' options + (HOST '127.0.0.1', + DATABASE 'db_legitimate', + USER 'root', + PASSWORD '', + PORT $SLAVE_MYPORT, + SOCKET '', + OWNER 'root'); + +create user guest_select@localhost; +grant select on federated.* to guest_select@localhost; + +create user guest_super@localhost; +grant select,SUPER,RELOAD on *.* to guest_super@localhost; + +create user guest_usage@localhost; +grant usage on *.* to guest_usage@localhost; + +CREATE TABLE federated.t1 ( + `id` int(20) NOT NULL, + `name` varchar(64) NOT NULL default '' + ) ENGINE = FEDERATED CONNECTION = 's1'; + +select * from federated.t1; + +connect (conn_select,127.0.0.1,guest_select,,federated,$MASTER_MYPORT); +connect (conn_usage,127.0.0.1,guest_usage,,,$MASTER_MYPORT); +connect (conn_super,127.0.0.1,guest_super,,,$MASTER_MYPORT); + +connection conn_select; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +alter server s1 options (database 'db_bogus'); + +connection master; +flush tables; +select * from federated.t1; + +connection conn_usage; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +alter server s1 options (database 'db_bogus'); + +connection master; +flush tables; +select * from federated.t1; + +connection conn_super; +alter server s1 options (database 'db_bogus'); + +connection master; +flush tables; +select * from federated.t1; + +connection conn_select; +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +drop server if exists 's1'; +--replace_result $SLAVE_MYPORT SLAVE_PORT +--error ER_SPECIFIC_ACCESS_DENIED_ERROR +eval create server 's1' foreign data wrapper 'mysql' options + (HOST '127.0.0.1', + DATABASE 'db_legitimate', + USER 'root', + PASSWORD '', + PORT $SLAVE_MYPORT, + SOCKET '', + OWNER 'root'); + +connection conn_super; +drop server 's1'; +--replace_result $SLAVE_MYPORT SLAVE_PORT +eval create server 's1' foreign data wrapper 'mysql' options + (HOST '127.0.0.1', + DATABASE 'db_legitimate', + USER 'root', + PASSWORD '', + PORT $SLAVE_MYPORT, + SOCKET '', + OWNER 'root'); + +connection master; +flush tables; +select * from federated.t1; + +# clean up test +connection slave; +drop database db_legitimate; +drop database db_bogus; + +disconnect conn_select; +disconnect conn_usage; +disconnect conn_super; + +connection master; +drop user guest_super@localhost; +drop user guest_usage@localhost; +drop user guest_select@localhost; +drop table federated.t1; +drop server 's1'; + + +--echo # End of 5.1 tests + + +# +# Bug#25721 - deadlock with ALTER/CREATE SERVER +# +connect (other,localhost,root,,); +connection master; +use test; +delimiter //; +create procedure p1 () +begin + DECLARE v INT DEFAULT 0; + DECLARE e INT DEFAULT 0; + DECLARE CONTINUE HANDLER FOR SQLEXCEPTION SET e = e + 1; + WHILE v < 10000 do + CREATE SERVER s + FOREIGN DATA WRAPPER mysql + OPTIONS (USER 'Remote', HOST '192.168.1.106', DATABASE 'test'); + ALTER SERVER s OPTIONS (USER 'Remote'); + DROP SERVER s; + SET v = v + 1; + END WHILE; + SELECT e > 0; +END// +delimiter ;// +connection other; +use test; +send call p1(); +connection master; +call p1(); +connection other; +reap; +drop procedure p1; +drop server if exists s; + + source include/federated_cleanup.inc; diff --git a/mysql-test/t/heap_btree.test b/mysql-test/t/heap_btree.test index 68aa79834fc8dc4cf6fc0eaef5e5959d8ef1ad74..4e7102806d6fd29317373aa046b8e0a72be6a1ce 100644 --- a/mysql-test/t/heap_btree.test +++ b/mysql-test/t/heap_btree.test @@ -182,6 +182,37 @@ delete from t1 where a >= 2; select a from t1 order by a; drop table t1; +# +# Bug#26996 - Update of a Field in a Memory Table ends with wrong result +# +CREATE TABLE t1 ( + c1 CHAR(3), + c2 INTEGER, + KEY USING BTREE(c1), + KEY USING BTREE(c2) +) ENGINE= MEMORY; +INSERT INTO t1 VALUES ('ABC',0), ('A',0), ('B',0), ('C',0); +UPDATE t1 SET c2= c2 + 1 WHERE c1 = 'A'; +SELECT * FROM t1; +DROP TABLE t1; + +# +# Bug#24985 - UTF8 ENUM primary key on MEMORY using BTREE +# causes incorrect duplicate entries +# +CREATE TABLE t1 ( + c1 ENUM('1', '2'), + UNIQUE USING BTREE(c1) +) ENGINE= MEMORY DEFAULT CHARSET= utf8; +INSERT INTO t1 VALUES('1'), ('2'); +DROP TABLE t1; +CREATE TABLE t1 ( + c1 SET('1', '2'), + UNIQUE USING BTREE(c1) +) ENGINE= MEMORY DEFAULT CHARSET= utf8; +INSERT INTO t1 VALUES('1'), ('2'); +DROP TABLE t1; + --echo End of 4.1 tests # @@ -205,3 +236,4 @@ INSERT INTO t1 VALUES(NULL),(NULL); DROP TABLE t1; --echo End of 5.0 tests + diff --git a/mysql-test/t/myisam.test b/mysql-test/t/myisam.test index 4281030fc3cea7244998475639d891b30c03206a..8f7357d1c9803fecd73fcac63b125f8e2a1027f8 100644 --- a/mysql-test/t/myisam.test +++ b/mysql-test/t/myisam.test @@ -874,6 +874,150 @@ CREATE TABLE t1 (c1 TEXT) AVG_ROW_LENGTH=70100 MAX_ROWS=4100100100; SHOW TABLE STATUS LIKE 't1'; DROP TABLE t1; +# +# Bug#26231 - select count(*) on myisam table returns wrong value +# when index is used +# +CREATE TABLE t1 (c1 TEXT NOT NULL, KEY c1 (c1(10))) ENGINE=MyISAM; +# Fill at least two key blocks. "Tab, A" must be in both blocks. +INSERT INTO t1 VALUES + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), (CHAR(9,65)), + (''), (''), (''), (''), + (' B'), (' B'), (' B'), (' B'); +SELECT DISTINCT COUNT(*) FROM t1 WHERE c1 = ''; +SELECT DISTINCT length(c1), c1 FROM t1 WHERE c1 = ''; +SELECT DISTINCT COUNT(*) FROM t1 IGNORE INDEX (c1) WHERE c1 = ''; +SELECT DISTINCT length(c1), c1 FROM t1 IGNORE INDEX (c1) WHERE c1 = ''; +SELECT DISTINCT length(c1), c1 FROM t1 ORDER BY c1; +DROP TABLE t1; + --echo End of 4.1 tests diff --git a/mysys/my_pread.c b/mysys/my_pread.c index 7a09c21e0392290eed8260269e84f9fa7893fbe5..f8f0fa49c10f04b66991b76334bc0fc496d6318b 100644 --- a/mysys/my_pread.c +++ b/mysys/my_pread.c @@ -37,7 +37,7 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset, errno=0; /* Linux doesn't reset this */ #endif #ifndef HAVE_PREAD - off_t old_offset; + os_off_t old_offset; pthread_mutex_lock(&my_file_info[Filedes].mutex); /* @@ -45,7 +45,7 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset, before seeking to the given offset */ - error= (old_offset= (off_t)lseek(Filedes, 0L, MY_SEEK_CUR)) == -1L || + error= (old_offset= lseek(Filedes, 0L, MY_SEEK_CUR)) == -1L || lseek(Filedes, offset, MY_SEEK_SET) == -1L; if (!error) /* Seek was successful */ @@ -116,7 +116,7 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, { #ifndef HAVE_PREAD int error= 0; - off_t old_offset; + os_off_t old_offset; writenbytes= (uint) -1; pthread_mutex_lock(&my_file_info[Filedes].mutex); @@ -124,7 +124,7 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, As we cannot change the file pointer, we save the old position, before seeking to the given offset */ - error= ((old_offset= (off_t)lseek(Filedes, 0L, MY_SEEK_CUR)) == -1L || + error= ((old_offset= lseek(Filedes, 0L, MY_SEEK_CUR)) == -1L || lseek(Filedes, offset, MY_SEEK_SET) == -1L); if (!error) /* Seek was successful */ diff --git a/mysys/my_pthread.c b/mysys/my_pthread.c index db01602f4ab4062d0d17f4287fde123adbd868fa..d8182b67442aafeb2b0700c849069b1ab513fd35 100644 --- a/mysys/my_pthread.c +++ b/mysys/my_pthread.c @@ -29,8 +29,6 @@ #define SCHED_POLICY SCHED_OTHER #endif -uint thd_lib_detected= 0; - uint thd_lib_detected; #ifndef my_pthread_setprio diff --git a/mysys/my_redel.c b/mysys/my_redel.c index 606d301e1d007d1b0dc9e6aa2a4d3d60e1290e7b..b12cf098283694c417c25dd5ac712f89b0628544 100644 --- a/mysys/my_redel.c +++ b/mysys/my_redel.c @@ -59,7 +59,7 @@ int my_redel(const char *org_name, const char *tmp_name, myf MyFlags) MyFlags)) goto end; } - else if (my_delete(org_name,MyFlags)) + else if (my_delete_allow_opened(org_name, MyFlags)) goto end; if (my_rename(tmp_name,org_name,MyFlags)) goto end; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 9a0bed8d31856375359be70d1f0156d601b88a7c..2bc8c2071d2a2cfe4f54319852f18da2f346efd5 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1445,6 +1445,9 @@ void close_system_tables(THD *thd, Open_tables_state *backup); TABLE *open_system_table_for_update(THD *thd, TABLE_LIST *one_table); bool close_cached_tables(THD *thd, bool wait_for_refresh, TABLE_LIST *tables, bool have_lock = FALSE); +bool close_cached_connection_tables(THD *thd, bool wait_for_refresh, + LEX_STRING *connect_string, + bool have_lock = FALSE); void copy_field_from_tmp_record(Field *field,int offset); bool fill_record(THD *thd, Field **field, List<Item> &values, bool ignore_errors); diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4d7c2c485ab83886f181e920013be66d2d4deb8b..f01f539ec516b5235b5fcb15aabb9b06ffad15a3 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -858,6 +858,7 @@ void free_io_cache(TABLE *table) DBUG_VOID_RETURN; } + /* Close all tables which aren't in use by any thread @@ -969,6 +970,71 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, } +/* + Close all tables which match specified connection string or + if specified string is NULL, then any table with a connection string. +*/ + +bool close_cached_connection_tables(THD *thd, bool if_wait_for_refresh, + LEX_STRING *connection, bool have_lock) +{ + uint idx; + TABLE_LIST tmp, *tables= NULL; + bool result= FALSE; + DBUG_ENTER("close_cached_connections"); + DBUG_ASSERT(thd); + + bzero(&tmp, sizeof(TABLE_LIST)); + + if (!have_lock) + VOID(pthread_mutex_lock(&LOCK_open)); + + for (idx= 0; idx < table_def_cache.records; idx++) + { + TABLE_SHARE *share= (TABLE_SHARE *) hash_element(&table_def_cache, idx); + + /* Ignore if table is not open or does not have a connect_string */ + if (!share->connect_string.length || !share->ref_count) + continue; + + /* Compare the connection string */ + if (connection && + (connection->length > share->connect_string.length || + (connection->length < share->connect_string.length && + (share->connect_string.str[connection->length] != '/' && + share->connect_string.str[connection->length] != '\\')) || + strncasecmp(connection->str, share->connect_string.str, + connection->length))) + continue; + + /* close_cached_tables() only uses these elements */ + tmp.db= share->db.str; + tmp.table_name= share->table_name.str; + tmp.next_local= tables; + + tables= (TABLE_LIST *) memdup_root(thd->mem_root, (char*)&tmp, + sizeof(TABLE_LIST)); + } + + if (tables) + result= close_cached_tables(thd, FALSE, tables, TRUE); + + if (!have_lock) + VOID(pthread_mutex_unlock(&LOCK_open)); + + if (if_wait_for_refresh) + { + pthread_mutex_lock(&thd->mysys_var->mutex); + thd->mysys_var->current_mutex= 0; + thd->mysys_var->current_cond= 0; + thd->proc_info=0; + pthread_mutex_unlock(&thd->mysys_var->mutex); + } + + DBUG_RETURN(result); +} + + /* Mark all tables in the list which were used by current substatement as free for reuse. diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 4c85ba252e56734e2771a253c5a4586ce5b0d54e..c94b43e231dde22b1bfce2204a48b3f25298483f 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -4274,6 +4274,10 @@ create_sp_error: int error; LEX *lex= thd->lex; DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER")); + + if (check_global_access(thd, SUPER_ACL)) + break; + if ((error= create_server(thd, &lex->server_options))) { DBUG_PRINT("info", ("problem creating server <%s>", @@ -4289,6 +4293,10 @@ create_sp_error: int error; LEX *lex= thd->lex; DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER")); + + if (check_global_access(thd, SUPER_ACL)) + break; + if ((error= alter_server(thd, &lex->server_options))) { DBUG_PRINT("info", ("problem altering server <%s>", @@ -4304,9 +4312,13 @@ create_sp_error: int err_code; LEX *lex= thd->lex; DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER")); + + if (check_global_access(thd, SUPER_ACL)) + break; + if ((err_code= drop_server(thd, &lex->server_options))) { - if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_EXISTS) + if (! lex->drop_if_exists && err_code == ER_FOREIGN_SERVER_DOESNT_EXIST) { DBUG_PRINT("info", ("problem dropping server %s", lex->server_options.server_name)); diff --git a/sql/sql_servers.cc b/sql/sql_servers.cc index 7b3b71cdd9a060c89d1bcfb5553c77d219fa55ae..d21864e857258d0ee3ea3db39dae97e8256c7846 100644 --- a/sql/sql_servers.cc +++ b/sql/sql_servers.cc @@ -16,6 +16,21 @@ /* The servers are saved in the system table "servers" + + Currently, when the user performs an ALTER SERVER or a DROP SERVER + operation, it will cause all open tables which refer to the named + server connection to be flushed. This may cause some undesirable + behaviour with regard to currently running transactions. It is + expected that the DBA knows what s/he is doing when s/he performs + the ALTER SERVER or DROP SERVER operation. + + TODO: + It is desirable for us to implement a callback mechanism instead where + callbacks can be registered for specific server protocols. The callback + will be fired when such a server name has been created/altered/dropped + or when statistics are to be gathered such as how many actual connections. + Storage engines etc will be able to make use of the callback so that + currently running transactions etc will not be disrupted. */ #include "mysql_priv.h" @@ -25,15 +40,43 @@ #include "sp_head.h" #include "sp.h" -static my_bool servers_load(THD *thd, TABLE_LIST *tables); -HASH servers_cache; -pthread_mutex_t servers_cache_mutex; // To init the hash -uint servers_cache_initialised=FALSE; -/* Version of server table. incremented by servers_load */ -static uint servers_version=0; +/* + We only use 1 mutex to guard the data structures - THR_LOCK_servers. + Read locked when only reading data and write-locked for all other access. +*/ + +static HASH servers_cache; static MEM_ROOT mem; static rw_lock_t THR_LOCK_servers; +static bool get_server_from_table_to_cache(TABLE *table); + +/* insert functions */ +static int insert_server(THD *thd, FOREIGN_SERVER *server_options); +static int insert_server_record(TABLE *table, FOREIGN_SERVER *server); +static int insert_server_record_into_cache(FOREIGN_SERVER *server); +static void prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, + FOREIGN_SERVER *server); +/* drop functions */ +static int delete_server_record(TABLE *table, + char *server_name, + int server_name_length); +static int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options); + +/* update functions */ +static void prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options, + FOREIGN_SERVER *existing, + FOREIGN_SERVER *altered); +static int update_server(THD *thd, FOREIGN_SERVER *existing, + FOREIGN_SERVER *altered); +static int update_server_record(TABLE *table, FOREIGN_SERVER *server); +static int update_server_record_in_cache(FOREIGN_SERVER *existing, + FOREIGN_SERVER *altered); +/* utility functions */ +static void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to); + + + static byte *servers_cache_get_key(FOREIGN_SERVER *server, uint *length, my_bool not_used __attribute__((unused))) { @@ -46,6 +89,7 @@ static byte *servers_cache_get_key(FOREIGN_SERVER *server, uint *length, DBUG_RETURN((byte*) server->server_name); } + /* Initialize structures responsible for servers used in federated server scheme information for them from the server @@ -65,35 +109,27 @@ static byte *servers_cache_get_key(FOREIGN_SERVER *server, uint *length, 1 Could not initialize servers */ -my_bool servers_init(bool dont_read_servers_table) +bool servers_init(bool dont_read_servers_table) { THD *thd; - my_bool return_val= 0; + bool return_val= FALSE; DBUG_ENTER("servers_init"); /* init the mutex */ - if (pthread_mutex_init(&servers_cache_mutex, MY_MUTEX_INIT_FAST)) - DBUG_RETURN(1); - if (my_rwlock_init(&THR_LOCK_servers, NULL)) - DBUG_RETURN(1); + DBUG_RETURN(TRUE); /* initialise our servers cache */ if (hash_init(&servers_cache, system_charset_info, 32, 0, 0, (hash_get_key) servers_cache_get_key, 0, 0)) { - return_val= 1; /* we failed, out of memory? */ + return_val= TRUE; /* we failed, out of memory? */ goto end; } /* Initialize the mem root for data */ init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0); - /* - at this point, the cache is initialised, let it be known - */ - servers_cache_initialised= TRUE; - if (dont_read_servers_table) goto end; @@ -101,7 +137,7 @@ my_bool servers_init(bool dont_read_servers_table) To be able to run this from boot, we allocate a temporary THD */ if (!(thd=new THD)) - DBUG_RETURN(1); + DBUG_RETURN(TRUE); thd->thread_stack= (char*) &thd; thd->store_globals(); /* @@ -131,19 +167,13 @@ end: TRUE Error */ -static my_bool servers_load(THD *thd, TABLE_LIST *tables) +static bool servers_load(THD *thd, TABLE_LIST *tables) { TABLE *table; READ_RECORD read_record_info; - my_bool return_val= TRUE; + bool return_val= TRUE; DBUG_ENTER("servers_load"); - if (!servers_cache_initialised) - DBUG_RETURN(0); - - /* need to figure out how to utilise this variable */ - servers_version++; /* servers updated */ - /* first, send all cached rows to sleep with the fishes, oblivion! I expect this crappy comment replaced */ free_root(&mem, MYF(MY_MARK_BLOCKS_FREE)); @@ -157,7 +187,7 @@ static my_bool servers_load(THD *thd, TABLE_LIST *tables) goto end; } - return_val=0; + return_val= FALSE; end: end_read_record(&read_record_info); @@ -184,10 +214,10 @@ end: TRUE Failure */ -my_bool servers_reload(THD *thd) +bool servers_reload(THD *thd) { TABLE_LIST tables[1]; - my_bool return_val= 1; + bool return_val= TRUE; DBUG_ENTER("servers_reload"); if (thd->locked_tables) @@ -197,10 +227,9 @@ my_bool servers_reload(THD *thd) close_thread_tables(thd); } - /* - To avoid deadlocks we should obtain table locks before - obtaining servers_cache->lock mutex. - */ + DBUG_PRINT("info", ("locking servers_cache")); + rw_wrlock(&THR_LOCK_servers); + bzero((char*) tables, sizeof(tables)); tables[0].alias= tables[0].table_name= (char*) "servers"; tables[0].db= (char*) "mysql"; @@ -213,12 +242,6 @@ my_bool servers_reload(THD *thd) goto end; } - DBUG_PRINT("info", ("locking servers_cache")); - VOID(pthread_mutex_lock(&servers_cache_mutex)); - - //old_servers_cache= servers_cache; - //old_mem=mem; - if ((return_val= servers_load(thd, tables))) { // Error. Revert to old list /* blast, for now, we have no servers, discuss later way to preserve */ @@ -227,14 +250,14 @@ my_bool servers_reload(THD *thd) servers_free(); } - DBUG_PRINT("info", ("unlocking servers_cache")); - VOID(pthread_mutex_unlock(&servers_cache_mutex)); - end: close_thread_tables(thd); + DBUG_PRINT("info", ("unlocking servers_cache")); + rw_unlock(&THR_LOCK_servers); DBUG_RETURN(return_val); } + /* Initialize structures responsible for servers used in federated server scheme information for them from the server @@ -261,7 +284,8 @@ end: 1 could not insert server struct into global servers cache */ -my_bool get_server_from_table_to_cache(TABLE *table) +static bool +get_server_from_table_to_cache(TABLE *table) { /* alloc a server struct */ char *ptr; @@ -309,68 +333,6 @@ my_bool get_server_from_table_to_cache(TABLE *table) DBUG_RETURN(FALSE); } -/* - SYNOPSIS - server_exists_in_table() - THD *thd - thread pointer - LEX_SERVER_OPTIONS *server_options - pointer to Lex->server_options - - NOTES - This function takes a LEX_SERVER_OPTIONS struct, which is very much the - same type of structure as a FOREIGN_SERVER, it contains the values parsed - in any one of the [CREATE|DELETE|DROP] SERVER statements. Using the - member "server_name", index_read_idx either founds the record and returns - 1, or doesn't find the record, and returns 0 - - RETURN VALUES - 0 record not found - 1 record found -*/ - -my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options) -{ - int result= 1; - int error= 0; - TABLE_LIST tables; - TABLE *table; - DBUG_ENTER("server_exists"); - - bzero((char*) &tables, sizeof(tables)); - tables.db= (char*) "mysql"; - tables.alias= tables.table_name= (char*) "servers"; - - /* need to open before acquiring THR_LOCK_plugin or it will deadlock */ - if (! (table= open_ltable(thd, &tables, TL_WRITE))) - DBUG_RETURN(TRUE); - - table->use_all_columns(); - - rw_wrlock(&THR_LOCK_servers); - VOID(pthread_mutex_lock(&servers_cache_mutex)); - - /* set the field that's the PK to the value we're looking for */ - table->field[0]->store(server_options->server_name, - server_options->server_name_length, - system_charset_info); - - if ((error= table->file->index_read_idx(table->record[0], 0, - (byte *)table->field[0]->ptr, HA_WHOLE_KEY, - HA_READ_KEY_EXACT))) - { - if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) - { - table->file->print_error(error, MYF(0)); - result= -1; - } - result= 0; - DBUG_PRINT("info",("record for server '%s' not found!", - server_options->server_name)); - } - - VOID(pthread_mutex_unlock(&servers_cache_mutex)); - rw_unlock(&THR_LOCK_servers); - DBUG_RETURN(result); -} /* SYNOPSIS @@ -382,15 +344,18 @@ my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options) This function takes a server object that is has all members properly prepared, ready to be inserted both into the mysql.servers table and the servers cache. + + THR_LOCK_servers must be write locked. RETURN VALUES 0 - no error other - error code */ -int insert_server(THD *thd, FOREIGN_SERVER *server) +static int +insert_server(THD *thd, FOREIGN_SERVER *server) { - int error= 0; + int error= -1; TABLE_LIST tables; TABLE *table; @@ -402,13 +367,7 @@ int insert_server(THD *thd, FOREIGN_SERVER *server) /* need to open before acquiring THR_LOCK_plugin or it will deadlock */ if (! (table= open_ltable(thd, &tables, TL_WRITE))) - DBUG_RETURN(TRUE); - - /* lock mutex to make sure no changes happen */ - VOID(pthread_mutex_lock(&servers_cache_mutex)); - - /* lock table */ - rw_wrlock(&THR_LOCK_servers); + goto end; /* insert the server into the table */ if ((error= insert_server_record(table, server))) @@ -419,12 +378,10 @@ int insert_server(THD *thd, FOREIGN_SERVER *server) goto end; end: - /* unlock the table */ - rw_unlock(&THR_LOCK_servers); - VOID(pthread_mutex_unlock(&servers_cache_mutex)); DBUG_RETURN(error); } + /* SYNOPSIS int insert_server_record_into_cache() @@ -434,13 +391,16 @@ end: This function takes a FOREIGN_SERVER pointer to an allocated (root mem) and inserts it into the global servers cache + THR_LOCK_servers must be write locked. + RETURN VALUE 0 - no error >0 - error code */ -int insert_server_record_into_cache(FOREIGN_SERVER *server) +static int +insert_server_record_into_cache(FOREIGN_SERVER *server) { int error=0; DBUG_ENTER("insert_server_record_into_cache"); @@ -461,6 +421,7 @@ int insert_server_record_into_cache(FOREIGN_SERVER *server) DBUG_RETURN(error); } + /* SYNOPSIS store_server_fields() @@ -478,7 +439,8 @@ int insert_server_record_into_cache(FOREIGN_SERVER *server) */ -void store_server_fields(TABLE *table, FOREIGN_SERVER *server) +static void +store_server_fields(TABLE *table, FOREIGN_SERVER *server) { table->use_all_columns(); @@ -539,6 +501,7 @@ void store_server_fields(TABLE *table, FOREIGN_SERVER *server) */ +static int insert_server_record(TABLE *table, FOREIGN_SERVER *server) { int error; @@ -605,9 +568,11 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server) int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) { - int error= 0; + int error; TABLE_LIST tables; TABLE *table; + LEX_STRING name= { server_options->server_name, + server_options->server_name_length }; DBUG_ENTER("drop_server"); DBUG_PRINT("info", ("server name server->server_name %s", @@ -617,28 +582,35 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) tables.db= (char*) "mysql"; tables.alias= tables.table_name= (char*) "servers"; - /* need to open before acquiring THR_LOCK_plugin or it will deadlock */ - if (! (table= open_ltable(thd, &tables, TL_WRITE))) - DBUG_RETURN(TRUE); - rw_wrlock(&THR_LOCK_servers); - VOID(pthread_mutex_lock(&servers_cache_mutex)); + /* hit the memory hit first */ + if ((error= delete_server_record_in_cache(server_options))) + goto end; - if ((error= delete_server_record(table, - server_options->server_name, - server_options->server_name_length))) + if (! (table= open_ltable(thd, &tables, TL_WRITE))) + { + error= my_errno; goto end; + } + error= delete_server_record(table, name.str, name.length); - if ((error= delete_server_record_in_cache(server_options))) - goto end; + /* close the servers table before we call closed_cached_connection_tables */ + close_thread_tables(thd); + + if (close_cached_connection_tables(thd, TRUE, &name)) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_UNKNOWN_ERROR, "Server connection in use"); + } end: - VOID(pthread_mutex_unlock(&servers_cache_mutex)); rw_unlock(&THR_LOCK_servers); DBUG_RETURN(error); } + + /* SYNOPSIS @@ -657,10 +629,10 @@ end: */ -int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options) +static int +delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options) { - - int error= 0; + int error= ER_FOREIGN_SERVER_DOESNT_EXIST; FOREIGN_SERVER *server; DBUG_ENTER("delete_server_record_in_cache"); @@ -676,7 +648,7 @@ int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options) DBUG_PRINT("info", ("server_name %s length %d not found!", server_options->server_name, server_options->server_name_length)); - // what should be done if not found in the cache? + goto end; } /* We succeded in deletion of the server to the table, now delete @@ -686,14 +658,15 @@ int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options) server->server_name, server->server_name_length)); - if (server) - VOID(hash_delete(&servers_cache, (byte*) server)); - - servers_version++; /* servers updated */ + VOID(hash_delete(&servers_cache, (byte*) server)); + + error= 0; +end: DBUG_RETURN(error); } + /* SYNOPSIS @@ -713,6 +686,8 @@ int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options) table for the particular server via the call to update_server_record, and in the servers_cache via update_server_record_in_cache. + THR_LOCK_servers must be write locked. + RETURN VALUE 0 - no error >0 - error code @@ -721,7 +696,7 @@ int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options) int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered) { - int error= 0; + int error; TABLE *table; TABLE_LIST tables; DBUG_ENTER("update_server"); @@ -731,19 +706,26 @@ int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered) tables.alias= tables.table_name= (char*)"servers"; if (!(table= open_ltable(thd, &tables, TL_WRITE))) - DBUG_RETURN(1); + { + error= my_errno; + goto end; + } - rw_wrlock(&THR_LOCK_servers); if ((error= update_server_record(table, altered))) goto end; - update_server_record_in_cache(existing, altered); + error= update_server_record_in_cache(existing, altered); + + /* + Perform a reload so we don't have a 'hole' in our mem_root + */ + servers_load(thd, &tables); end: - rw_unlock(&THR_LOCK_servers); DBUG_RETURN(error); } + /* SYNOPSIS @@ -760,6 +742,8 @@ end: HASH, then the updated record inserted, in essence replacing the old record. + THR_LOCK_servers must be write locked. + RETURN VALUE 0 - no error 1 - error @@ -790,13 +774,13 @@ int update_server_record_in_cache(FOREIGN_SERVER *existing, { DBUG_PRINT("info", ("had a problem inserting server %s at %lx", altered->server_name, (long unsigned int) altered)); - error= 1; + error= ER_OUT_OF_RESOURCES; } - servers_version++; /* servers updated */ DBUG_RETURN(error); } + /* SYNOPSIS @@ -829,9 +813,9 @@ void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to) to->password= strdup_root(&mem, from->password); if (to->port == -1) to->port= from->port; - if (!to->socket) + if (!to->socket && from->socket) to->socket= strdup_root(&mem, from->socket); - if (!to->scheme) + if (!to->scheme && from->scheme) to->scheme= strdup_root(&mem, from->scheme); if (!to->owner) to->owner= strdup_root(&mem, from->owner); @@ -839,6 +823,7 @@ void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to) DBUG_VOID_RETURN; } + /* SYNOPSIS @@ -861,7 +846,9 @@ void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to) */ -int update_server_record(TABLE *table, FOREIGN_SERVER *server) + +static int +update_server_record(TABLE *table, FOREIGN_SERVER *server) { int error=0; DBUG_ENTER("update_server_record"); @@ -876,10 +863,7 @@ int update_server_record(TABLE *table, FOREIGN_SERVER *server) HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) - { table->file->print_error(error, MYF(0)); - error= 1; - } DBUG_PRINT("info",("server not found!")); error= ER_FOREIGN_SERVER_DOESNT_EXIST; } @@ -899,6 +883,7 @@ end: DBUG_RETURN(error); } + /* SYNOPSIS @@ -914,11 +899,11 @@ end: */ -int delete_server_record(TABLE *table, - char *server_name, - int server_name_length) +static int +delete_server_record(TABLE *table, + char *server_name, int server_name_length) { - int error= 0; + int error; DBUG_ENTER("delete_server_record"); table->use_all_columns(); @@ -930,10 +915,7 @@ int delete_server_record(TABLE *table, HA_READ_KEY_EXACT))) { if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) - { table->file->print_error(error, MYF(0)); - error= 1; - } DBUG_PRINT("info",("server not found!")); error= ER_FOREIGN_SERVER_DOESNT_EXIST; } @@ -962,28 +944,35 @@ int delete_server_record(TABLE *table, int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options) { - int error; + int error= ER_FOREIGN_SERVER_EXISTS; FOREIGN_SERVER *server; DBUG_ENTER("create_server"); DBUG_PRINT("info", ("server_options->server_name %s", server_options->server_name)); + rw_wrlock(&THR_LOCK_servers); + + /* hit the memory first */ + if (hash_search(&servers_cache, (byte*) server_options->server_name, + server_options->server_name_length)) + goto end; + server= (FOREIGN_SERVER *)alloc_root(&mem, sizeof(FOREIGN_SERVER)); - if ((error= prepare_server_struct_for_insert(server_options, server))) - goto end; + prepare_server_struct_for_insert(server_options, server); - if ((error= insert_server(thd, server))) - goto end; + error= insert_server(thd, server); DBUG_PRINT("info", ("error returned %d", error)); end: + rw_unlock(&THR_LOCK_servers); DBUG_RETURN(error); } + /* SYNOPSIS @@ -1000,37 +989,44 @@ end: int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options) { - int error= 0; + int error= ER_FOREIGN_SERVER_DOESNT_EXIST; FOREIGN_SERVER *altered, *existing; + LEX_STRING name= { server_options->server_name, + server_options->server_name_length }; DBUG_ENTER("alter_server"); DBUG_PRINT("info", ("server_options->server_name %s", server_options->server_name)); + rw_wrlock(&THR_LOCK_servers); + + if (!(existing= (FOREIGN_SERVER *) hash_search(&servers_cache, + (byte*) name.str, + name.length))) + goto end; + altered= (FOREIGN_SERVER *)alloc_root(&mem, sizeof(FOREIGN_SERVER)); - VOID(pthread_mutex_lock(&servers_cache_mutex)); + prepare_server_struct_for_update(server_options, existing, altered); - if (!(existing= (FOREIGN_SERVER *) hash_search(&servers_cache, - (byte*) server_options->server_name, - server_options->server_name_length))) - { - error= ER_FOREIGN_SERVER_DOESNT_EXIST; - goto end; - } + error= update_server(thd, existing, altered); - if ((error= prepare_server_struct_for_update(server_options, existing, altered))) - goto end; + /* close the servers table before we call closed_cached_connection_tables */ + close_thread_tables(thd); - if ((error= update_server(thd, existing, altered))) - goto end; + if (close_cached_connection_tables(thd, FALSE, &name)) + { + push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN, + ER_UNKNOWN_ERROR, "Server connection in use"); + } end: DBUG_PRINT("info", ("error returned %d", error)); - VOID(pthread_mutex_unlock(&servers_cache_mutex)); + rw_unlock(&THR_LOCK_servers); DBUG_RETURN(error); } + /* SYNOPSIS @@ -1041,19 +1037,17 @@ end: NOTES RETURN VALUE - 0 - no error + none */ -int prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, - FOREIGN_SERVER *server) +static void +prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, + FOREIGN_SERVER *server) { - int error; char *unset_ptr= (char*)""; DBUG_ENTER("prepare_server_struct"); - error= 0; - /* these two MUST be set */ server->server_name= strdup_root(&mem, server_options->server_name); server->server_name_length= server_options->server_name_length; @@ -1083,7 +1077,7 @@ int prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, server->owner= server_options->owner ? strdup_root(&mem, server_options->owner) : unset_ptr; - DBUG_RETURN(error); + DBUG_VOID_RETURN; } /* @@ -1099,13 +1093,12 @@ int prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, */ -int prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options, - FOREIGN_SERVER *existing, - FOREIGN_SERVER *altered) +static void +prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options, + FOREIGN_SERVER *existing, + FOREIGN_SERVER *altered) { - int error; DBUG_ENTER("prepare_server_struct_for_update"); - error= 0; altered->server_name= strdup_root(&mem, server_options->server_name); altered->server_name_length= server_options->server_name_length; @@ -1156,7 +1149,7 @@ int prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options, (strcmp(server_options->owner, existing->owner))) ? strdup_root(&mem, server_options->owner) : 0; - DBUG_RETURN(error); + DBUG_VOID_RETURN; } /* @@ -1175,16 +1168,65 @@ int prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options, void servers_free(bool end) { DBUG_ENTER("servers_free"); - if (!servers_cache_initialised) + if (!hash_inited(&servers_cache)) + DBUG_VOID_RETURN; + if (!end) + { + free_root(&mem, MYF(MY_MARK_BLOCKS_FREE)); + my_hash_reset(&servers_cache); DBUG_VOID_RETURN; - VOID(pthread_mutex_destroy(&servers_cache_mutex)); - servers_cache_initialised=0; + } + rwlock_destroy(&THR_LOCK_servers); free_root(&mem,MYF(0)); hash_free(&servers_cache); DBUG_VOID_RETURN; } +/* + SYNOPSIS + + clone_server(MEM_ROOT *mem_root, FOREIGN_SERVER *orig, FOREIGN_SERVER *buff) + + Create a clone of FOREIGN_SERVER. If the supplied mem_root is of + thd->mem_root then the copy is automatically disposed at end of statement. + + NOTES + + ARGS + MEM_ROOT pointer (strings are copied into this mem root) + FOREIGN_SERVER pointer (made a copy of) + FOREIGN_SERVER buffer (if not-NULL, this pointer is returned) + + RETURN VALUE + FOREIGN_SEVER pointer (copy of one supplied FOREIGN_SERVER) +*/ + +static FOREIGN_SERVER *clone_server(MEM_ROOT *mem, const FOREIGN_SERVER *server, + FOREIGN_SERVER *buffer) +{ + DBUG_ENTER("sql_server.cc:clone_server"); + + if (!buffer) + buffer= (FOREIGN_SERVER *) alloc_root(mem, sizeof(FOREIGN_SERVER)); + + buffer->server_name= strmake_root(mem, server->server_name, + server->server_name_length); + buffer->port= server->port; + buffer->server_name_length= server->server_name_length; + + /* TODO: We need to examine which of these can really be NULL */ + buffer->db= server->db ? strdup_root(mem, server->db) : NULL; + buffer->scheme= server->scheme ? strdup_root(mem, server->scheme) : NULL; + buffer->username= server->username? strdup_root(mem, server->username): NULL; + buffer->password= server->password? strdup_root(mem, server->password): NULL; + buffer->socket= server->socket ? strdup_root(mem, server->socket) : NULL; + buffer->owner= server->owner ? strdup_root(mem, server->owner) : NULL; + buffer->host= server->host ? strdup_root(mem, server->host) : NULL; + + DBUG_RETURN(buffer); +} + /* @@ -1199,11 +1241,11 @@ void servers_free(bool end) */ -FOREIGN_SERVER *get_server_by_name(const char *server_name) +FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name, + FOREIGN_SERVER *buff) { - ulong error_num=0; uint server_name_length; - FOREIGN_SERVER *server= 0; + FOREIGN_SERVER *server; DBUG_ENTER("get_server_by_name"); DBUG_PRINT("info", ("server_name %s", server_name)); @@ -1212,12 +1254,11 @@ FOREIGN_SERVER *get_server_by_name(const char *server_name) if (! server_name || !strlen(server_name)) { DBUG_PRINT("info", ("server_name not defined!")); - error_num= 1; DBUG_RETURN((FOREIGN_SERVER *)NULL); } DBUG_PRINT("info", ("locking servers_cache")); - VOID(pthread_mutex_lock(&servers_cache_mutex)); + rw_rdlock(&THR_LOCK_servers); if (!(server= (FOREIGN_SERVER *) hash_search(&servers_cache, (byte*) server_name, server_name_length))) @@ -1226,8 +1267,12 @@ FOREIGN_SERVER *get_server_by_name(const char *server_name) server_name, server_name_length)); server= (FOREIGN_SERVER *) NULL; } + /* otherwise, make copy of server */ + else + server= clone_server(mem, server, buff); + DBUG_PRINT("info", ("unlocking servers_cache")); - VOID(pthread_mutex_unlock(&servers_cache_mutex)); + rw_unlock(&THR_LOCK_servers); DBUG_RETURN(server); } diff --git a/sql/sql_servers.h b/sql/sql_servers.h index 23b8cefd5bb1f0ba4e4bd46f8995ce4224026960..63c691893d1ec39ab1c7711775a8d3b82925d9ae 100644 --- a/sql/sql_servers.h +++ b/sql/sql_servers.h @@ -25,40 +25,19 @@ typedef struct st_federated_server } FOREIGN_SERVER; /* cache handlers */ -my_bool servers_init(bool dont_read_server_table); -my_bool servers_reload(THD *thd); -my_bool get_server_from_table_to_cache(TABLE *table); +bool servers_init(bool dont_read_server_table); +bool servers_reload(THD *thd); void servers_free(bool end=0); /* insert functions */ int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options); -int insert_server(THD *thd, FOREIGN_SERVER *server_options); -int insert_server_record(TABLE *table, FOREIGN_SERVER *server); -int insert_server_record_into_cache(FOREIGN_SERVER *server); -void store_server_fields_for_insert(TABLE *table, FOREIGN_SERVER *server); -void store_server_fields_for_insert(TABLE *table, - FOREIGN_SERVER *existing, - FOREIGN_SERVER *altered); -int prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, - FOREIGN_SERVER *server); /* drop functions */ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options); -int delete_server_record(TABLE *table, - char *server_name, - int server_name_length); -int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options); /* update functions */ int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options); -int prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options, - FOREIGN_SERVER *existing, - FOREIGN_SERVER *altered); -int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered); -int update_server_record(TABLE *table, FOREIGN_SERVER *server); -int update_server_record_in_cache(FOREIGN_SERVER *existing, - FOREIGN_SERVER *altered); -/* utility functions */ -void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to); -FOREIGN_SERVER *get_server_by_name(const char *server_name); -my_bool server_exists_in_table(THD *thd, char *server_name); + +/* lookup functions */ +FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name, + FOREIGN_SERVER *server_buffer); diff --git a/storage/federated/ha_federated.cc b/storage/federated/ha_federated.cc index 441c1785e74b2d83c281b0cdf3ff7d6569b1f4fe..aa7184268f5c6f868084dcd67a4b0a020bee82b7 100644 --- a/storage/federated/ha_federated.cc +++ b/storage/federated/ha_federated.cc @@ -43,23 +43,55 @@ The create table will simply create the .frm file, and within the "CREATE TABLE" SQL, there SHALL be any of the following : - comment=scheme://username:password@hostname:port/database/tablename - comment=scheme://username@hostname/database/tablename - comment=scheme://username:password@hostname/database/tablename - comment=scheme://username:password@hostname/database/tablename + connection=scheme://username:password@hostname:port/database/tablename + connection=scheme://username@hostname/database/tablename + connection=scheme://username:password@hostname/database/tablename + connection=scheme://username:password@hostname/database/tablename + + - OR - + + As of 5.1 (See worklog #3031), federated now allows you to use a non-url + format, taking advantage of mysql.servers: + + connection="connection_one" + connection="connection_one/table_foo" An example would be: - comment=mysql://username:password@hostname:port/database/tablename + connection=mysql://username:password@hostname:port/database/tablename - ***IMPORTANT*** + or, if we had: + + create server 'server_one' foreign data wrapper 'mysql' options + (HOST '127.0.0.1', + DATABASE 'db1', + USER 'root', + PASSWORD '', + PORT 3306, + SOCKET '', + OWNER 'root'); + + CREATE TABLE federated.t1 ( + `id` int(20) NOT NULL, + `name` varchar(64) NOT NULL default '' + ) + ENGINE="FEDERATED" DEFAULT CHARSET=latin1 + CONNECTION='server_one'; + + So, this will have been the equivalent of - This is a first release, conceptual release - Only 'mysql://' is supported at this release. + CONNECTION="mysql://root@127.0.0.1:3306/db1/t1" + Then, we can also change the server to point to a new schema: - This comment connection string is necessary for the handler to be - able to connect to the foreign server. + ALTER SERVER 'server_one' options(DATABASE 'db2'); + + All subsequent calls will now be against db2.t1! Guess what? You don't + have to perform an alter table! + + This connecton="connection string" is necessary for the handler to be + able to connect to the foreign server, either by URL, or by server + name. The basic flow is this: @@ -166,7 +198,7 @@ KEY other_key (other)) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 - COMMENT='root@127.0.0.1:9306/federated/test_federated'; + CONNECTION='mysql://root@127.0.0.1:9306/federated/test_federated'; Notice the "COMMENT" and "ENGINE" field? This is where you respectively set the engine type, "FEDERATED" and foreign @@ -263,7 +295,7 @@ To run these tests, go into ./mysql-test (based in the directory you built the server in) - ./mysql-test-run federatedd + ./mysql-test-run federated To run the test, or if you want to run the test and have debug info: @@ -311,7 +343,7 @@ ------------- These were the files that were modified or created for this - Federated handler to work: + Federated handler to work, in 5.0: ./configure.in ./sql/Makefile.am @@ -329,6 +361,13 @@ ./sql/ha_federated.cc ./sql/ha_federated.h + In 5.1 + + my:~/mysql-build/mysql-5.1-bkbits patg$ ls storage/federated/ + CMakeLists.txt Makefile.in ha_federated.h plug.in + Makefile SCCS libfederated.a + Makefile.am ha_federated.cc libfederated_a-ha_federated.o + */ @@ -546,42 +585,39 @@ static int parse_url_error(FEDERATED_SHARE *share, TABLE *table, int error_num) int buf_len; DBUG_ENTER("ha_federated parse_url_error"); - if (share->connection_string) - { - DBUG_PRINT("info", - ("error: parse_url. Returning error code %d \ - freeing share->connection_string %lx", - error_num, (long unsigned int) share->connection_string)); - my_free((gptr) share->connection_string, MYF(0)); - share->connection_string= 0; - } buf_len= min(table->s->connect_string.length, FEDERATED_QUERY_BUFFER_SIZE-1); strmake(buf, table->s->connect_string.str, buf_len); my_error(error_num, MYF(0), buf); DBUG_RETURN(error_num); } + /* retrieve server object which contains server meta-data from the system table given a server's name, set share connection parameter members */ -int get_connection(FEDERATED_SHARE *share) +int get_connection(MEM_ROOT *mem_root, FEDERATED_SHARE *share) { int error_num= ER_FOREIGN_SERVER_DOESNT_EXIST; char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; - FOREIGN_SERVER *server; + FOREIGN_SERVER *server, server_buffer; DBUG_ENTER("ha_federated::get_connection"); + /* + get_server_by_name() clones the server if exists and allocates + copies of strings in the supplied mem_root + */ if (!(server= - get_server_by_name(share->connection_string))) + get_server_by_name(mem_root, share->connection_string, &server_buffer))) { DBUG_PRINT("info", ("get_server_by_name returned > 0 error condition!")); /* need to come up with error handling */ error_num=1; goto error; } - DBUG_PRINT("info", ("get_server_by_name returned server at %lx", (long unsigned int) server)); + DBUG_PRINT("info", ("get_server_by_name returned server at %lx", + (long unsigned int) server)); /* Most of these should never be empty strings, error handling will @@ -590,29 +626,22 @@ int get_connection(FEDERATED_SHARE *share) except there are errors in the trace file of the share being overrun at the address of the share. */ - if (server->server_name) - share->server_name= server->server_name; - share->server_name_length= server->server_name_length ? - server->server_name_length : 0; - if (server->username) - share->username= server->username; - if (server->password) - share->password= server->password; - if (server->db) - share->database= server->db; - - share->port= server->port ? (ushort) server->port : MYSQL_PORT; - - if (server->host) - share->hostname= server->host; - if (server->socket) - share->socket= server->socket; - else if (strcmp(share->hostname, my_localhost) == 0) - share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0)); - if (server->scheme) - share->scheme= server->scheme; - else - share->scheme= NULL; + share->server_name_length= server->server_name_length; + share->server_name= server->server_name; + share->username= server->username; + share->password= server->password; + share->database= server->db; +#ifndef I_AM_PARANOID + share->port= server->port > 0 && server->port < 65536 ? +#else + share->port= server->port > 1023 && server->port < 65536 ? +#endif + (ushort) server->port : MYSQL_PORT; + share->hostname= server->host; + if (!(share->socket= server->socket) && + !strcmp(share->hostname, my_localhost)) + share->socket= (char *) MYSQL_UNIX_ADDR; + share->scheme= server->scheme; DBUG_PRINT("info", ("share->username %s", share->username)); DBUG_PRINT("info", ("share->password %s", share->password)); @@ -635,6 +664,7 @@ error: SYNOPSIS parse_url() + mem_root MEM_ROOT pointer for memory allocation share pointer to FEDERATED share table pointer to current TABLE class table_create_flag determines what error to throw @@ -684,7 +714,7 @@ error: */ -static int parse_url(FEDERATED_SHARE *share, TABLE *table, +static int parse_url(MEM_ROOT *mem_root, FEDERATED_SHARE *share, TABLE *table, uint table_create_flag) { uint error_num= (table_create_flag ? @@ -698,20 +728,19 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, DBUG_PRINT("info", ("Length: %d", table->s->connect_string.length)); DBUG_PRINT("info", ("String: '%.*s'", table->s->connect_string.length, table->s->connect_string.str)); - share->connection_string= my_strndup(table->s->connect_string.str, - table->s->connect_string.length, - MYF(0)); + share->connection_string= strmake_root(mem_root, table->s->connect_string.str, + table->s->connect_string.length); - // Add a null for later termination of table name - share->connection_string[table->s->connect_string.length]= 0; DBUG_PRINT("info",("parse_url alloced share->connection_string %lx", (long unsigned int) share->connection_string)); DBUG_PRINT("info",("share->connection_string %s",share->connection_string)); - /* No delimiters, must be a straight connection name */ - if ( (!strchr(share->connection_string, '/')) && - (!strchr(share->connection_string, '@')) && - (!strchr(share->connection_string, ';'))) + /* + No :// or @ in connection string. Must be a straight connection name of + either "servername" or "servername/tablename" + */ + if ( (!strstr(share->connection_string, "://") && + (!strchr(share->connection_string, '@')))) { DBUG_PRINT("info", @@ -720,17 +749,51 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, share->connection_string, (long unsigned int) share->connection_string)); + /* ok, so we do a little parsing, but not completely! */ share->parsed= FALSE; - if ((error_num= get_connection(share))) - goto error; + /* + If there is a single '/' in the connection string, this means the user is + specifying a table name + */ + + if ((share->table_name= strchr(share->connection_string, '/'))) + { + share->connection_string[share->table_name - share->connection_string]= '\0'; + share->table_name++; + share->table_name_length= strlen(share->table_name); + DBUG_PRINT("info", + ("internal format, parsed table_name share->connection_string \ + %s share->table_name %s", + share->connection_string, share->table_name)); + + /* + there better not be any more '/'s ! + */ + if (strchr(share->table_name, '/')) + goto error; + + } /* - connection specifies everything but, resort to - expecting remote and foreign table names to match + otherwise, straight server name, use tablename of federated table + as remote table name */ - share->table_name= table->s->table_name.str; - share->table_name_length= table->s->table_name.length; - share->table_name[share->table_name_length]= '\0'; + else + { + /* + connection specifies everything but, resort to + expecting remote and foreign table names to match + */ + share->table_name= strmake_root(mem_root, table->s->table_name.str, + (share->table_name_length= table->s->table_name.length)); + DBUG_PRINT("info", + ("internal format, default table_name share->connection_string \ + %s share->table_name %s", + share->connection_string, share->table_name)); + } + + if ((error_num= get_connection(mem_root, share))) + goto error; } else { @@ -816,7 +879,7 @@ Then password is a null string, so set to NULL if (!share->port) { if (strcmp(share->hostname, my_localhost) == 0) - share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0)); + share->socket= (char *) MYSQL_UNIX_ADDR; else share->port= MYSQL_PORT; } @@ -1420,22 +1483,26 @@ err: static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) { - char *select_query; char query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; Field **field; String query(query_buffer, sizeof(query_buffer), &my_charset_bin); FEDERATED_SHARE *share= NULL, tmp_share; + MEM_ROOT mem_root; + DBUG_ENTER("ha_federated.cc::get_share"); + /* In order to use this string, we must first zero it's length, or it will contain garbage */ query.length(0); + init_alloc_root(&mem_root, 256, 0); + pthread_mutex_lock(&federated_mutex); tmp_share.share_key= table_name; tmp_share.share_key_length= strlen(table_name); - if (parse_url(&tmp_share, table, 0)) + if (parse_url(&mem_root, &tmp_share, table, 0)) goto error; /* TODO: change tmp_share.scheme to LEX_STRING object */ @@ -1456,24 +1523,17 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) query.length(query.length() - sizeof_trailing_comma); query.append(STRING_WITH_LEN(" FROM `")); + query.append(tmp_share.table_name, tmp_share.table_name_length); + query.append(STRING_WITH_LEN("`")); + DBUG_PRINT("info", ("calling alloc_root")); - if (!(share= (FEDERATED_SHARE *) - my_multi_malloc(MYF(MY_WME), - &share, sizeof(*share), - &select_query, - query.length()+table->s->connect_string.length+1, - NullS))) + if (!(share= (FEDERATED_SHARE *) memdup_root(&mem_root, (char*)&tmp_share, sizeof(*share))) || + !(share->select_query= (char*) strmake_root(&mem_root, query.ptr(), query.length()))) goto error; - memcpy(share, &tmp_share, sizeof(tmp_share)); - - share->table_name_length= strlen(share->table_name); - /* TODO: share->table_name to LEX_STRING object */ - query.append(share->table_name, share->table_name_length); - query.append(STRING_WITH_LEN("`")); - share->select_query= select_query; - strmov(share->select_query, query.ptr()); share->use_count= 0; + share->mem_root= mem_root; + DBUG_PRINT("info", ("share->select_query %s", share->select_query)); @@ -1482,17 +1542,18 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) thr_lock_init(&share->lock); pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST); } + else + free_root(&mem_root, MYF(0)); /* prevents memory leak */ + share->use_count++; pthread_mutex_unlock(&federated_mutex); - return share; + DBUG_RETURN(share); error: pthread_mutex_unlock(&federated_mutex); - my_free((gptr) tmp_share.connection_string, MYF(MY_ALLOW_ZERO_PTR)); - tmp_share.connection_string= 0; - my_free((gptr) share, MYF(MY_ALLOW_ZERO_PTR)); - return NULL; + free_root(&mem_root, MYF(0)); + DBUG_RETURN(NULL); } @@ -1504,23 +1565,16 @@ error: static int free_share(FEDERATED_SHARE *share) { + MEM_ROOT mem_root= share->mem_root; DBUG_ENTER("free_share"); pthread_mutex_lock(&federated_mutex); if (!--share->use_count) { hash_delete(&federated_open_tables, (byte*) share); - if (share->parsed) - my_free((gptr) share->socket, MYF(MY_ALLOW_ZERO_PTR)); - /*if (share->connection_string) - { - */ - my_free((gptr) share->connection_string, MYF(MY_ALLOW_ZERO_PTR)); - share->connection_string= 0; - /*}*/ thr_lock_delete(&share->lock); VOID(pthread_mutex_destroy(&share->mutex)); - my_free((gptr) share, MYF(0)); + free_root(&mem_root, MYF(0)); } pthread_mutex_unlock(&federated_mutex); @@ -1589,6 +1643,8 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) mysql_options(mysql,MYSQL_SET_CHARSET_NAME, this->table->s->table_charset->csname); + DBUG_PRINT("info", ("calling mysql_real_connect hostname %s user %s", + share->hostname, share->username)); if (!mysql || !mysql_real_connect(mysql, share->hostname, share->username, @@ -2831,15 +2887,13 @@ int ha_federated::create(const char *name, TABLE *table_arg, HA_CREATE_INFO *create_info) { int retval; + THD *thd= current_thd; FEDERATED_SHARE tmp_share; // Only a temporary share, to test the url DBUG_ENTER("ha_federated::create"); - if (!(retval= parse_url(&tmp_share, table_arg, 1))) + if (!(retval= parse_url(thd->mem_root, &tmp_share, table_arg, 1))) retval= check_foreign_data_source(&tmp_share, 1); - /* free this because strdup created it in parse_url */ - my_free((gptr) tmp_share.connection_string, MYF(MY_ALLOW_ZERO_PTR)); - tmp_share.connection_string= 0; DBUG_RETURN(retval); } diff --git a/storage/federated/ha_federated.h b/storage/federated/ha_federated.h index bbc2b2fe9f878456eaae077247755729748a6979..4d2eefdd98663e897d9f598e5d682223264af77b 100644 --- a/storage/federated/ha_federated.h +++ b/storage/federated/ha_federated.h @@ -43,6 +43,8 @@ The example implements the minimum of what you will probably need. */ typedef struct st_federated_share { + MEM_ROOT mem_root; + bool parsed; /* this key is unique db/tablename */ const char *share_key; @@ -67,6 +69,7 @@ typedef struct st_federated_share { char *sport; int share_key_length; ushort port; + uint table_name_length, server_name_length, connect_string_length, use_count; pthread_mutex_t mutex; THR_LOCK lock; diff --git a/storage/heap/ha_heap.cc b/storage/heap/ha_heap.cc index 5831ec6167ac6265b1c1d73a586968aec5135268..8c378f7334f0fdb8a6c39d89fefc8f20a66ee2c7 100644 --- a/storage/heap/ha_heap.cc +++ b/storage/heap/ha_heap.cc @@ -628,7 +628,10 @@ int ha_heap::create(const char *name, TABLE *table_arg, seg->length= (uint) key_part->length; seg->flag= key_part->key_part_flag; - seg->charset= field->charset(); + if (field->flags & (ENUM_FLAG | SET_FLAG)) + seg->charset= &my_charset_bin; + else + seg->charset= field->charset(); if (field->null_ptr) { seg->null_bit= field->null_bit; diff --git a/storage/heap/hp_write.c b/storage/heap/hp_write.c index 86e79c9d7ecbab87e91c0dc9db12f4b2d4713fe5..19215fcf01733c1e17bdf80f24351c75754f0158 100644 --- a/storage/heap/hp_write.c +++ b/storage/heap/hp_write.c @@ -105,7 +105,6 @@ int hp_rb_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *record, heap_rb_param custom_arg; uint old_allocated; - info->last_pos= NULL; /* For heap_rnext/heap_rprev */ custom_arg.keyseg= keyinfo->seg; custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos); if (keyinfo->flag & HA_NOSAME) diff --git a/storage/myisam/ha_myisam.cc b/storage/myisam/ha_myisam.cc index 8fe4d988dbc67fc9adf63a48c8c608d0e993e6f7..d31f5b7e792e4d159b7dcd6bab8753b620fe1a88 100644 --- a/storage/myisam/ha_myisam.cc +++ b/storage/myisam/ha_myisam.cc @@ -635,6 +635,9 @@ bool ha_myisam::check_if_locking_is_allowed(uint sql_command, int ha_myisam::open(const char *name, int mode, uint test_if_locked) { + MI_KEYDEF *keyinfo; + MI_COLUMNDEF *recinfo= 0; + uint recs; uint i; /* @@ -657,6 +660,26 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked) if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER))) return (my_errno ? my_errno : -1); + if (!table->s->tmp_table) /* No need to perform a check for tmp table */ + { + if ((my_errno= table2myisam(table, &keyinfo, &recinfo, &recs))) + { + /* purecov: begin inspected */ + DBUG_PRINT("error", ("Failed to convert TABLE object to MyISAM " + "key and column definition")); + goto err; + /* purecov: end */ + } + if (check_definition(keyinfo, recinfo, table->s->keys, recs, + file->s->keyinfo, file->s->rec, + file->s->base.keys, file->s->base.fields, true)) + { + /* purecov: begin inspected */ + my_errno= HA_ERR_CRASHED; + goto err; + /* purecov: end */ + } + } if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE)) VOID(mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0)); @@ -677,7 +700,18 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked) (struct st_mysql_ftparser *)parser->plugin->info; table->key_info[i].block_size= file->s->keyinfo[i].block_length; } - return (0); + my_errno= 0; + goto end; + err: + this->close(); + end: + /* + Both recinfo and keydef are allocated by my_multi_malloc(), thus only + recinfo must be freed. + */ + if (recinfo) + my_free((gptr) recinfo, MYF(0)); + return my_errno; } int ha_myisam::close(void) @@ -1023,6 +1057,22 @@ int ha_myisam::repair(THD *thd, MI_CHECK ¶m, bool do_optimize) ha_rows rows= file->state->records; DBUG_ENTER("ha_myisam::repair"); + /* + Normally this method is entered with a properly opened table. If the + repair fails, it can be repeated with more elaborate options. Under + special circumstances it can happen that a repair fails so that it + closed the data file and cannot re-open it. In this case file->dfile + is set to -1. We must not try another repair without an open data + file. (Bug #25289) + */ + if (file->dfile == -1) + { + sql_print_information("Retrying repair of: '%s' failed. " + "Please try REPAIR EXTENDED or myisamchk", + table->s->path.str); + DBUG_RETURN(HA_ADMIN_FAILED); + } + param.db_name= table->s->db.str; param.table_name= table->alias; param.tmpfile_createflag = O_RDWR | O_TRUNC; diff --git a/storage/myisam/mi_create.c b/storage/myisam/mi_create.c index 5dd4a98127edc118a2e41fbcc98b460ea1c761d8..71d377c8b6b070e5c1b21095706699fcdb0ba561 100644 --- a/storage/myisam/mi_create.c +++ b/storage/myisam/mi_create.c @@ -573,6 +573,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, pthread_mutex_lock(&THR_LOCK_myisam); + /* + NOTE: For test_if_reopen() we need a real path name. Hence we need + MY_RETURN_REAL_PATH for every fn_format(filename, ...). + */ if (ci->index_file_name) { char *iext= strrchr(ci->index_file_name, '.'); @@ -584,13 +588,14 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, if ((path= strrchr(ci->index_file_name, FN_LIBCHAR))) *path= '\0'; fn_format(filename, name, ci->index_file_name, MI_NAME_IEXT, - MY_REPLACE_DIR | MY_UNPACK_FILENAME | MY_APPEND_EXT); + MY_REPLACE_DIR | MY_UNPACK_FILENAME | + MY_RETURN_REAL_PATH | MY_APPEND_EXT); } else { fn_format(filename, ci->index_file_name, "", MI_NAME_IEXT, - MY_UNPACK_FILENAME | (have_iext ? MY_REPLACE_EXT : - MY_APPEND_EXT)); + MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | + (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT)); } fn_format(linkname, name, "", MI_NAME_IEXT, MY_UNPACK_FILENAME|MY_APPEND_EXT); @@ -603,10 +608,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, } else { + char *iext= strrchr(name, '.'); + int have_iext= iext && !strcmp(iext, MI_NAME_IEXT); fn_format(filename, name, "", MI_NAME_IEXT, - (MY_UNPACK_FILENAME | - (flags & HA_DONT_TOUCH_DATA) ? MY_RETURN_REAL_PATH : 0) | - MY_APPEND_EXT); + MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH | + (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT)); linkname_ptr=0; /* Replace the current file */ create_flag=MY_DELETE_OLD; @@ -618,6 +624,9 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, A TRUNCATE command checks for the table in the cache only and could be fooled to believe, the table is not open. Pull the emergency brake in this situation. (Bug #8306) + + NOTE: The filename is compared against unique_file_name of every + open table. Hence we need a real path here. */ if (test_if_reopen(filename)) { diff --git a/storage/myisam/mi_range.c b/storage/myisam/mi_range.c index 2cdb02b2c809709673818b69b9999942e1b332ab..c7ab6731a2c9bb828aeb16eb0f7425bad6d15aa2 100644 --- a/storage/myisam/mi_range.c +++ b/storage/myisam/mi_range.c @@ -138,8 +138,42 @@ static ha_rows _mi_record_pos(MI_INFO *info, const byte *key, if (!(nextflag & (SEARCH_FIND | SEARCH_NO_FIND | SEARCH_LAST))) key_len=USE_WHOLE_KEY; + /* + my_handler.c:mi_compare_text() has a flag 'skip_end_space'. + This is set in my_handler.c:ha_key_cmp() in dependence on the + compare flags 'nextflag' and the column type. + + TEXT columns are of type HA_KEYTYPE_VARTEXT. In this case the + condition is skip_end_space= ((nextflag & (SEARCH_FIND | + SEARCH_UPDATE)) == SEARCH_FIND). + + SEARCH_FIND is used for an exact key search. The combination + SEARCH_FIND | SEARCH_UPDATE is used in write/update/delete + operations with a comment like "Not real duplicates", whatever this + means. From the condition above we can see that 'skip_end_space' is + always false for these operations. The result is that trailing space + counts in key comparison and hence, emtpy strings ('', string length + zero, but not NULL) compare less that strings starting with control + characters and these in turn compare less than strings starting with + blanks. + + When estimating the number of records in a key range, we request an + exact search for the minimum key. This translates into a plain + SEARCH_FIND flag. Using this alone would lead to a 'skip_end_space' + compare. Empty strings would be expected above control characters. + Their keys would not be found because they are located below control + characters. + + This is the reason that we add the SEARCH_UPDATE flag here. It makes + the key estimation compare in the same way like key write operations + do. Olny so we will find the keys where they have been inserted. + + Adding the flag unconditionally does not hurt as it is used in the + above mentioned condition only. So it can safely be used together + with other flags. + */ pos=_mi_search_pos(info,keyinfo,key_buff,key_len, - nextflag | SEARCH_SAVE_BUFF, + nextflag | SEARCH_SAVE_BUFF | SEARCH_UPDATE, info->s->state.key_root[inx]); if (pos >= 0.0) { diff --git a/storage/myisam/mi_search.c b/storage/myisam/mi_search.c index 8d2b68a97f0b83b02283d63d3fe5c3188d1f3f03..d313619e00722940f17a1afa92b74b5a90a56999 100644 --- a/storage/myisam/mi_search.c +++ b/storage/myisam/mi_search.c @@ -926,11 +926,16 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, /* Keys are compressed the following way: - prefix length Packed length of prefix for the prev key. (1 or 3 bytes) + prefix length Packed length of prefix common with prev key (1 or 3 bytes) for each key segment: [is null] Null indicator if can be null (1 byte, zero means null) [length] Packed length if varlength (1 or 3 bytes) + key segment 'length' bytes of key segment value pointer Reference to the data file (last_keyseg->length). + + get_key_length() is a macro. It gets the prefix length from 'page' + and puts it into 'length'. It increments 'page' by 1 or 3, depending + on the packed length of the prefix length. */ get_key_length(length,page); if (length) @@ -945,34 +950,44 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); /* Wrong key */ } - from=key; from_end=key+length; + /* Key is packed against prev key, take prefix from prev key. */ + from= key; + from_end= key + length; } else { - from=page; from_end=page_end; /* Not packed key */ + /* Key is not packed against prev key, take all from page buffer. */ + from= page; + from_end= page_end; } /* - The trouble is that key is split in two parts: - The first part is in from ...from_end-1. - The second part starts at page + The trouble is that key can be split in two parts: + The first part (prefix) is in from .. from_end - 1. + The second part starts at page. + The split can be at every byte position. So we need to check for + the end of the first part before using every byte. */ for (keyseg=keyinfo->seg ; keyseg->type ;keyseg++) { if (keyseg->flag & HA_NULL_PART) { + /* If prefix is used up, switch to rest. */ if (from == from_end) { from=page; from_end=page_end; } if (!(*key++ = *from++)) continue; /* Null part */ } if (keyseg->flag & (HA_VAR_LENGTH_PART | HA_BLOB_PART | HA_SPACE_PACK)) { - /* Get length of dynamic length key part */ + /* If prefix is used up, switch to rest. */ if (from == from_end) { from=page; from_end=page_end; } + /* Get length of dynamic length key part */ if ((length= (*key++ = *from++)) == 255) { + /* If prefix is used up, switch to rest. */ if (from == from_end) { from=page; from_end=page_end; } length= (uint) ((*key++ = *from++)) << 8; + /* If prefix is used up, switch to rest. */ if (from == from_end) { from=page; from_end=page_end; } length+= (uint) ((*key++ = *from++)); } @@ -992,14 +1007,26 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, key+=length; from+=length; } + /* + Last segment (type == 0) contains length of data pointer. + If we have mixed key blocks with data pointer and key block pointer, + we have to copy both. + */ length=keyseg->length+nod_flag; if ((tmp=(uint) (from_end-from)) <= length) { + /* Remaining length is less or equal max possible length. */ memcpy(key+tmp,page,length-tmp); /* Get last part of key */ *page_pos= page+length-tmp; } else { + /* + Remaining length is greater than max possible length. + This can happen only if we switched to the new key bytes already. + 'page_end' is calculated with MI_MAX_KEY_BUFF. So it can be far + behind the real end of the key. + */ if (from_end != page_end) { DBUG_PRINT("error",("Error when unpacking key")); @@ -1007,6 +1034,7 @@ uint _mi_get_binary_pack_key(register MI_KEYDEF *keyinfo, uint nod_flag, my_errno=HA_ERR_CRASHED; DBUG_RETURN(0); /* Error */ } + /* Copy data pointer and, if appropriate, key block pointer. */ memcpy((byte*) key,(byte*) from,(size_t) length); *page_pos= from+length; }