Commit 74519b98 authored by unknown's avatar unknown

Merge bk-internal.mysql.com:/home/bk/mysql-5.1-engines

into  chilla.local:/home/mydev/mysql-5.1-axmrg


sql/mysql_priv.h:
  Auto merged
sql/sql_base.cc:
  Auto merged
sql/sql_parse.cc:
  Auto merged
sql/sql_servers.h:
  Auto merged
storage/federated/ha_federated.cc:
  Auto merged
storage/heap/ha_heap.cc:
  Auto merged
storage/myisam/ha_myisam.cc:
  Auto merged
sql/sql_servers.cc:
  Manual merge
parents 8f93150d 548aad25
...@@ -20,6 +20,14 @@ CREATE TABLE first_db.t1 ( ...@@ -20,6 +20,14 @@ CREATE TABLE first_db.t1 (
`name` varchar(64) NOT NULL default '' `name` varchar(64) NOT NULL default ''
) )
DEFAULT CHARSET=latin1; 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; use second_db;
DROP TABLE IF EXISTS second_db.t1; DROP TABLE IF EXISTS second_db.t1;
Warnings: Warnings:
...@@ -29,6 +37,14 @@ CREATE TABLE second_db.t1 ( ...@@ -29,6 +37,14 @@ CREATE TABLE second_db.t1 (
`name` varchar(64) NOT NULL default '' `name` varchar(64) NOT NULL default ''
) )
DEFAULT CHARSET=latin1; 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'; drop server if exists 'server_one';
create server 'server_one' foreign data wrapper 'mysql' options create server 'server_one' foreign data wrapper 'mysql' options
(HOST '127.0.0.1', (HOST '127.0.0.1',
...@@ -60,10 +76,10 @@ CREATE TABLE federated.old ( ...@@ -60,10 +76,10 @@ CREATE TABLE federated.old (
) )
ENGINE="FEDERATED" DEFAULT CHARSET=latin1 ENGINE="FEDERATED" DEFAULT CHARSET=latin1
CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/first_db/t1'; 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; SELECT * FROM federated.old;
id name id name
1 federated.old url 1 federated.old-> first_db.t1, url format
DROP TABLE IF EXISTS federated.old2; DROP TABLE IF EXISTS federated.old2;
Warnings: Warnings:
Note 1051 Unknown table 'old2' Note 1051 Unknown table 'old2'
...@@ -72,8 +88,37 @@ CREATE TABLE federated.old2 ( ...@@ -72,8 +88,37 @@ CREATE TABLE federated.old2 (
`name` varchar(64) NOT NULL default '' `name` varchar(64) NOT NULL default ''
) )
ENGINE="FEDERATED" DEFAULT CHARSET=latin1 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'; 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; DROP TABLE IF EXISTS federated.t1;
Warnings: Warnings:
Note 1051 Unknown table 't1' Note 1051 Unknown table 't1'
...@@ -83,18 +128,38 @@ CREATE TABLE federated.t1 ( ...@@ -83,18 +128,38 @@ CREATE TABLE federated.t1 (
) )
ENGINE="FEDERATED" DEFAULT CHARSET=latin1 ENGINE="FEDERATED" DEFAULT CHARSET=latin1
CONNECTION='server_one'; 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; SELECT * FROM federated.t1;
id name id name
1 federated.old url 1 federated.old-> first_db.t1, url format
1 server_one, new scheme 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'); ALTER SERVER 'server_one' options(DATABASE 'second_db');
flush tables; INSERT INTO federated.t1 (id, name) values (1, 'server_two, new scheme, second_db.t1');
INSERT INTO federated.t1 (id, name) values (1, 'server_two, new scheme');
SELECT * FROM federated.t1; SELECT * FROM federated.t1;
id name id name
1 federated.old2 url 1 federated.urldb2t1 -> second_db.t1, url format
1 server_two, new scheme 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 table federated.t1;
drop server 'server_one'; drop server 'server_one';
drop server 'server_two'; drop server 'server_two';
...@@ -104,6 +169,116 @@ drop table first_db.t1; ...@@ -104,6 +169,116 @@ drop table first_db.t1;
drop table second_db.t1; drop table second_db.t1;
drop database first_db; drop database first_db;
drop database second_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 TABLE IF EXISTS federated.t1;
DROP DATABASE IF EXISTS federated; DROP DATABASE IF EXISTS federated;
DROP TABLE IF EXISTS federated.t1; DROP TABLE IF EXISTS federated.t1;
......
...@@ -280,6 +280,33 @@ a ...@@ -280,6 +280,33 @@ a
1 1
1 1
drop table t1; 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 End of 4.1 tests
CREATE TABLE t1(val INT, KEY USING BTREE(val)) ENGINE=memory; CREATE TABLE t1(val INT, KEY USING BTREE(val)) ENGINE=memory;
INSERT INTO t1 VALUES(0); INSERT INTO t1 VALUES(0);
......
...@@ -17,6 +17,13 @@ CREATE TABLE first_db.t1 ( ...@@ -17,6 +17,13 @@ CREATE TABLE first_db.t1 (
) )
DEFAULT CHARSET=latin1; 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; use second_db;
DROP TABLE IF EXISTS second_db.t1; DROP TABLE IF EXISTS second_db.t1;
CREATE TABLE second_db.t1 ( CREATE TABLE second_db.t1 (
...@@ -25,6 +32,13 @@ CREATE TABLE second_db.t1 ( ...@@ -25,6 +32,13 @@ CREATE TABLE second_db.t1 (
) )
DEFAULT CHARSET=latin1; 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; connection master;
drop server if exists 'server_one'; drop server if exists 'server_one';
...@@ -61,7 +75,7 @@ eval CREATE TABLE federated.old ( ...@@ -61,7 +75,7 @@ eval CREATE TABLE federated.old (
ENGINE="FEDERATED" DEFAULT CHARSET=latin1 ENGINE="FEDERATED" DEFAULT CHARSET=latin1
CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/first_db/t1'; 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; SELECT * FROM federated.old;
...@@ -72,9 +86,32 @@ eval CREATE TABLE federated.old2 ( ...@@ -72,9 +86,32 @@ eval CREATE TABLE federated.old2 (
`name` varchar(64) NOT NULL default '' `name` varchar(64) NOT NULL default ''
) )
ENGINE="FEDERATED" DEFAULT CHARSET=latin1 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'; 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; DROP TABLE IF EXISTS federated.t1;
CREATE TABLE federated.t1 ( CREATE TABLE federated.t1 (
...@@ -84,17 +121,30 @@ CREATE TABLE federated.t1 ( ...@@ -84,17 +121,30 @@ CREATE TABLE federated.t1 (
ENGINE="FEDERATED" DEFAULT CHARSET=latin1 ENGINE="FEDERATED" DEFAULT CHARSET=latin1
CONNECTION='server_one'; 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; 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'); 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; 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 table federated.t1;
drop server 'server_one'; drop server 'server_one';
...@@ -107,4 +157,166 @@ drop table second_db.t1; ...@@ -107,4 +157,166 @@ drop table second_db.t1;
drop database first_db; drop database first_db;
drop database second_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; source include/federated_cleanup.inc;
...@@ -182,6 +182,37 @@ delete from t1 where a >= 2; ...@@ -182,6 +182,37 @@ delete from t1 where a >= 2;
select a from t1 order by a; select a from t1 order by a;
drop table t1; 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 --echo End of 4.1 tests
# #
......
...@@ -37,7 +37,7 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset, ...@@ -37,7 +37,7 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
errno=0; /* Linux doesn't reset this */ errno=0; /* Linux doesn't reset this */
#endif #endif
#ifndef HAVE_PREAD #ifndef HAVE_PREAD
off_t old_offset; os_off_t old_offset;
pthread_mutex_lock(&my_file_info[Filedes].mutex); 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, ...@@ -45,7 +45,7 @@ uint my_pread(File Filedes, byte *Buffer, uint Count, my_off_t offset,
before seeking to the given 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; lseek(Filedes, offset, MY_SEEK_SET) == -1L;
if (!error) /* Seek was successful */ if (!error) /* Seek was successful */
...@@ -116,7 +116,7 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset, ...@@ -116,7 +116,7 @@ uint my_pwrite(int Filedes, const byte *Buffer, uint Count, my_off_t offset,
{ {
#ifndef HAVE_PREAD #ifndef HAVE_PREAD
int error= 0; int error= 0;
off_t old_offset; os_off_t old_offset;
writenbytes= (uint) -1; writenbytes= (uint) -1;
pthread_mutex_lock(&my_file_info[Filedes].mutex); 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, ...@@ -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, As we cannot change the file pointer, we save the old position,
before seeking to the given 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); lseek(Filedes, offset, MY_SEEK_SET) == -1L);
if (!error) /* Seek was successful */ if (!error) /* Seek was successful */
......
...@@ -1445,6 +1445,9 @@ void close_system_tables(THD *thd, Open_tables_state *backup); ...@@ -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); 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_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); void copy_field_from_tmp_record(Field *field,int offset);
bool fill_record(THD *thd, Field **field, List<Item> &values, bool fill_record(THD *thd, Field **field, List<Item> &values,
bool ignore_errors); bool ignore_errors);
......
...@@ -858,6 +858,7 @@ void free_io_cache(TABLE *table) ...@@ -858,6 +858,7 @@ void free_io_cache(TABLE *table)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/* /*
Close all tables which aren't in use by any thread 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, ...@@ -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 Mark all tables in the list which were used by current substatement
as free for reuse. as free for reuse.
......
...@@ -4274,6 +4274,10 @@ create_sp_error: ...@@ -4274,6 +4274,10 @@ create_sp_error:
int error; int error;
LEX *lex= thd->lex; LEX *lex= thd->lex;
DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER")); DBUG_PRINT("info", ("case SQLCOM_CREATE_SERVER"));
if (check_global_access(thd, SUPER_ACL))
break;
if ((error= create_server(thd, &lex->server_options))) if ((error= create_server(thd, &lex->server_options)))
{ {
DBUG_PRINT("info", ("problem creating server <%s>", DBUG_PRINT("info", ("problem creating server <%s>",
...@@ -4289,6 +4293,10 @@ create_sp_error: ...@@ -4289,6 +4293,10 @@ create_sp_error:
int error; int error;
LEX *lex= thd->lex; LEX *lex= thd->lex;
DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER")); DBUG_PRINT("info", ("case SQLCOM_ALTER_SERVER"));
if (check_global_access(thd, SUPER_ACL))
break;
if ((error= alter_server(thd, &lex->server_options))) if ((error= alter_server(thd, &lex->server_options)))
{ {
DBUG_PRINT("info", ("problem altering server <%s>", DBUG_PRINT("info", ("problem altering server <%s>",
...@@ -4304,9 +4312,13 @@ create_sp_error: ...@@ -4304,9 +4312,13 @@ create_sp_error:
int err_code; int err_code;
LEX *lex= thd->lex; LEX *lex= thd->lex;
DBUG_PRINT("info", ("case SQLCOM_DROP_SERVER")); 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 ((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", DBUG_PRINT("info", ("problem dropping server %s",
lex->server_options.server_name)); lex->server_options.server_name));
......
...@@ -16,6 +16,21 @@ ...@@ -16,6 +16,21 @@
/* /*
The servers are saved in the system table "servers" 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" #include "mysql_priv.h"
...@@ -25,15 +40,43 @@ ...@@ -25,15 +40,43 @@
#include "sp_head.h" #include "sp_head.h"
#include "sp.h" #include "sp.h"
static my_bool servers_load(THD *thd, TABLE_LIST *tables); /*
HASH servers_cache; We only use 1 mutex to guard the data structures - THR_LOCK_servers.
pthread_mutex_t servers_cache_mutex; // To init the hash Read locked when only reading data and write-locked for all other access.
uint servers_cache_initialised=FALSE; */
/* Version of server table. incremented by servers_load */
static uint servers_version=0; static HASH servers_cache;
static MEM_ROOT mem; static MEM_ROOT mem;
static rw_lock_t THR_LOCK_servers; 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, static byte *servers_cache_get_key(FOREIGN_SERVER *server, uint *length,
my_bool not_used __attribute__((unused))) my_bool not_used __attribute__((unused)))
{ {
...@@ -46,6 +89,7 @@ static byte *servers_cache_get_key(FOREIGN_SERVER *server, uint *length, ...@@ -46,6 +89,7 @@ static byte *servers_cache_get_key(FOREIGN_SERVER *server, uint *length,
DBUG_RETURN((byte*) server->server_name); DBUG_RETURN((byte*) server->server_name);
} }
/* /*
Initialize structures responsible for servers used in federated Initialize structures responsible for servers used in federated
server scheme information for them from the server server scheme information for them from the server
...@@ -65,35 +109,27 @@ static byte *servers_cache_get_key(FOREIGN_SERVER *server, uint *length, ...@@ -65,35 +109,27 @@ static byte *servers_cache_get_key(FOREIGN_SERVER *server, uint *length,
1 Could not initialize servers 1 Could not initialize servers
*/ */
my_bool servers_init(bool dont_read_servers_table) bool servers_init(bool dont_read_servers_table)
{ {
THD *thd; THD *thd;
my_bool return_val= 0; bool return_val= FALSE;
DBUG_ENTER("servers_init"); DBUG_ENTER("servers_init");
/* init the mutex */ /* 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)) if (my_rwlock_init(&THR_LOCK_servers, NULL))
DBUG_RETURN(1); DBUG_RETURN(TRUE);
/* initialise our servers cache */ /* initialise our servers cache */
if (hash_init(&servers_cache, system_charset_info, 32, 0, 0, if (hash_init(&servers_cache, system_charset_info, 32, 0, 0,
(hash_get_key) servers_cache_get_key, 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; goto end;
} }
/* Initialize the mem root for data */ /* Initialize the mem root for data */
init_alloc_root(&mem, ACL_ALLOC_BLOCK_SIZE, 0); 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) if (dont_read_servers_table)
goto end; goto end;
...@@ -101,7 +137,7 @@ my_bool servers_init(bool dont_read_servers_table) ...@@ -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 To be able to run this from boot, we allocate a temporary THD
*/ */
if (!(thd=new THD)) if (!(thd=new THD))
DBUG_RETURN(1); DBUG_RETURN(TRUE);
thd->thread_stack= (char*) &thd; thd->thread_stack= (char*) &thd;
thd->store_globals(); thd->store_globals();
/* /*
...@@ -131,19 +167,13 @@ end: ...@@ -131,19 +167,13 @@ end:
TRUE Error TRUE Error
*/ */
static my_bool servers_load(THD *thd, TABLE_LIST *tables) static bool servers_load(THD *thd, TABLE_LIST *tables)
{ {
TABLE *table; TABLE *table;
READ_RECORD read_record_info; READ_RECORD read_record_info;
my_bool return_val= TRUE; bool return_val= TRUE;
DBUG_ENTER("servers_load"); 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! /* first, send all cached rows to sleep with the fishes, oblivion!
I expect this crappy comment replaced */ I expect this crappy comment replaced */
free_root(&mem, MYF(MY_MARK_BLOCKS_FREE)); free_root(&mem, MYF(MY_MARK_BLOCKS_FREE));
...@@ -157,7 +187,7 @@ static my_bool servers_load(THD *thd, TABLE_LIST *tables) ...@@ -157,7 +187,7 @@ static my_bool servers_load(THD *thd, TABLE_LIST *tables)
goto end; goto end;
} }
return_val=0; return_val= FALSE;
end: end:
end_read_record(&read_record_info); end_read_record(&read_record_info);
...@@ -184,10 +214,10 @@ end: ...@@ -184,10 +214,10 @@ end:
TRUE Failure TRUE Failure
*/ */
my_bool servers_reload(THD *thd) bool servers_reload(THD *thd)
{ {
TABLE_LIST tables[1]; TABLE_LIST tables[1];
my_bool return_val= 1; bool return_val= TRUE;
DBUG_ENTER("servers_reload"); DBUG_ENTER("servers_reload");
if (thd->locked_tables) if (thd->locked_tables)
...@@ -197,10 +227,9 @@ my_bool servers_reload(THD *thd) ...@@ -197,10 +227,9 @@ my_bool servers_reload(THD *thd)
close_thread_tables(thd); close_thread_tables(thd);
} }
/* DBUG_PRINT("info", ("locking servers_cache"));
To avoid deadlocks we should obtain table locks before rw_wrlock(&THR_LOCK_servers);
obtaining servers_cache->lock mutex.
*/
bzero((char*) tables, sizeof(tables)); bzero((char*) tables, sizeof(tables));
tables[0].alias= tables[0].table_name= (char*) "servers"; tables[0].alias= tables[0].table_name= (char*) "servers";
tables[0].db= (char*) "mysql"; tables[0].db= (char*) "mysql";
...@@ -213,12 +242,6 @@ my_bool servers_reload(THD *thd) ...@@ -213,12 +242,6 @@ my_bool servers_reload(THD *thd)
goto end; 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))) if ((return_val= servers_load(thd, tables)))
{ // Error. Revert to old list { // Error. Revert to old list
/* blast, for now, we have no servers, discuss later way to preserve */ /* blast, for now, we have no servers, discuss later way to preserve */
...@@ -227,14 +250,14 @@ my_bool servers_reload(THD *thd) ...@@ -227,14 +250,14 @@ my_bool servers_reload(THD *thd)
servers_free(); servers_free();
} }
DBUG_PRINT("info", ("unlocking servers_cache"));
VOID(pthread_mutex_unlock(&servers_cache_mutex));
end: end:
close_thread_tables(thd); close_thread_tables(thd);
DBUG_PRINT("info", ("unlocking servers_cache"));
rw_unlock(&THR_LOCK_servers);
DBUG_RETURN(return_val); DBUG_RETURN(return_val);
} }
/* /*
Initialize structures responsible for servers used in federated Initialize structures responsible for servers used in federated
server scheme information for them from the server server scheme information for them from the server
...@@ -261,7 +284,8 @@ end: ...@@ -261,7 +284,8 @@ end:
1 could not insert server struct into global servers cache 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 */ /* alloc a server struct */
char *ptr; char *ptr;
...@@ -309,68 +333,6 @@ my_bool get_server_from_table_to_cache(TABLE *table) ...@@ -309,68 +333,6 @@ my_bool get_server_from_table_to_cache(TABLE *table)
DBUG_RETURN(FALSE); 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 SYNOPSIS
...@@ -383,14 +345,17 @@ my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options) ...@@ -383,14 +345,17 @@ my_bool server_exists_in_table(THD *thd, LEX_SERVER_OPTIONS *server_options)
prepared, ready to be inserted both into the mysql.servers table and prepared, ready to be inserted both into the mysql.servers table and
the servers cache. the servers cache.
THR_LOCK_servers must be write locked.
RETURN VALUES RETURN VALUES
0 - no error 0 - no error
other - error code 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_LIST tables;
TABLE *table; TABLE *table;
...@@ -402,13 +367,7 @@ int insert_server(THD *thd, FOREIGN_SERVER *server) ...@@ -402,13 +367,7 @@ int insert_server(THD *thd, FOREIGN_SERVER *server)
/* need to open before acquiring THR_LOCK_plugin or it will deadlock */ /* need to open before acquiring THR_LOCK_plugin or it will deadlock */
if (! (table= open_ltable(thd, &tables, TL_WRITE))) if (! (table= open_ltable(thd, &tables, TL_WRITE)))
DBUG_RETURN(TRUE); goto end;
/* lock mutex to make sure no changes happen */
VOID(pthread_mutex_lock(&servers_cache_mutex));
/* lock table */
rw_wrlock(&THR_LOCK_servers);
/* insert the server into the table */ /* insert the server into the table */
if ((error= insert_server_record(table, server))) if ((error= insert_server_record(table, server)))
...@@ -419,12 +378,10 @@ int insert_server(THD *thd, FOREIGN_SERVER *server) ...@@ -419,12 +378,10 @@ int insert_server(THD *thd, FOREIGN_SERVER *server)
goto end; goto end;
end: end:
/* unlock the table */
rw_unlock(&THR_LOCK_servers);
VOID(pthread_mutex_unlock(&servers_cache_mutex));
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/* /*
SYNOPSIS SYNOPSIS
int insert_server_record_into_cache() int insert_server_record_into_cache()
...@@ -434,13 +391,16 @@ end: ...@@ -434,13 +391,16 @@ end:
This function takes a FOREIGN_SERVER pointer to an allocated (root mem) This function takes a FOREIGN_SERVER pointer to an allocated (root mem)
and inserts it into the global servers cache and inserts it into the global servers cache
THR_LOCK_servers must be write locked.
RETURN VALUE RETURN VALUE
0 - no error 0 - no error
>0 - error code >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; int error=0;
DBUG_ENTER("insert_server_record_into_cache"); DBUG_ENTER("insert_server_record_into_cache");
...@@ -461,6 +421,7 @@ int insert_server_record_into_cache(FOREIGN_SERVER *server) ...@@ -461,6 +421,7 @@ int insert_server_record_into_cache(FOREIGN_SERVER *server)
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/* /*
SYNOPSIS SYNOPSIS
store_server_fields() store_server_fields()
...@@ -478,7 +439,8 @@ int insert_server_record_into_cache(FOREIGN_SERVER *server) ...@@ -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(); table->use_all_columns();
...@@ -539,6 +501,7 @@ void store_server_fields(TABLE *table, FOREIGN_SERVER *server) ...@@ -539,6 +501,7 @@ void store_server_fields(TABLE *table, FOREIGN_SERVER *server)
*/ */
static
int insert_server_record(TABLE *table, FOREIGN_SERVER *server) int insert_server_record(TABLE *table, FOREIGN_SERVER *server)
{ {
int error; int error;
...@@ -605,9 +568,11 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server) ...@@ -605,9 +568,11 @@ int insert_server_record(TABLE *table, FOREIGN_SERVER *server)
int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
{ {
int error= 0; int error;
TABLE_LIST tables; TABLE_LIST tables;
TABLE *table; TABLE *table;
LEX_STRING name= { server_options->server_name,
server_options->server_name_length };
DBUG_ENTER("drop_server"); DBUG_ENTER("drop_server");
DBUG_PRINT("info", ("server name server->server_name %s", DBUG_PRINT("info", ("server name server->server_name %s",
...@@ -617,28 +582,35 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options) ...@@ -617,28 +582,35 @@ int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
tables.db= (char*) "mysql"; tables.db= (char*) "mysql";
tables.alias= tables.table_name= (char*) "servers"; 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); 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, if (! (table= open_ltable(thd, &tables, TL_WRITE)))
server_options->server_name, {
server_options->server_name_length))) error= my_errno;
goto end; goto end;
}
error= delete_server_record(table, name.str, name.length);
if ((error= delete_server_record_in_cache(server_options))) /* close the servers table before we call closed_cached_connection_tables */
goto end; 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: end:
VOID(pthread_mutex_unlock(&servers_cache_mutex));
rw_unlock(&THR_LOCK_servers); rw_unlock(&THR_LOCK_servers);
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/* /*
SYNOPSIS SYNOPSIS
...@@ -657,10 +629,10 @@ end: ...@@ -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= ER_FOREIGN_SERVER_DOESNT_EXIST;
int error= 0;
FOREIGN_SERVER *server; FOREIGN_SERVER *server;
DBUG_ENTER("delete_server_record_in_cache"); DBUG_ENTER("delete_server_record_in_cache");
...@@ -676,7 +648,7 @@ int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options) ...@@ -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!", DBUG_PRINT("info", ("server_name %s length %d not found!",
server_options->server_name, server_options->server_name,
server_options->server_name_length)); 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 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) ...@@ -686,14 +658,15 @@ int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options)
server->server_name, server->server_name,
server->server_name_length)); server->server_name_length));
if (server)
VOID(hash_delete(&servers_cache, (byte*) server)); VOID(hash_delete(&servers_cache, (byte*) server));
servers_version++; /* servers updated */ error= 0;
end:
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/* /*
SYNOPSIS SYNOPSIS
...@@ -713,6 +686,8 @@ int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options) ...@@ -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, table for the particular server via the call to update_server_record,
and in the servers_cache via update_server_record_in_cache. and in the servers_cache via update_server_record_in_cache.
THR_LOCK_servers must be write locked.
RETURN VALUE RETURN VALUE
0 - no error 0 - no error
>0 - error code >0 - error code
...@@ -721,7 +696,7 @@ int delete_server_record_in_cache(LEX_SERVER_OPTIONS *server_options) ...@@ -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 update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered)
{ {
int error= 0; int error;
TABLE *table; TABLE *table;
TABLE_LIST tables; TABLE_LIST tables;
DBUG_ENTER("update_server"); DBUG_ENTER("update_server");
...@@ -731,19 +706,26 @@ int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered) ...@@ -731,19 +706,26 @@ int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered)
tables.alias= tables.table_name= (char*)"servers"; tables.alias= tables.table_name= (char*)"servers";
if (!(table= open_ltable(thd, &tables, TL_WRITE))) 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))) if ((error= update_server_record(table, altered)))
goto end; 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: end:
rw_unlock(&THR_LOCK_servers);
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/* /*
SYNOPSIS SYNOPSIS
...@@ -760,6 +742,8 @@ end: ...@@ -760,6 +742,8 @@ end:
HASH, then the updated record inserted, in essence replacing the old HASH, then the updated record inserted, in essence replacing the old
record. record.
THR_LOCK_servers must be write locked.
RETURN VALUE RETURN VALUE
0 - no error 0 - no error
1 - error 1 - error
...@@ -790,13 +774,13 @@ int update_server_record_in_cache(FOREIGN_SERVER *existing, ...@@ -790,13 +774,13 @@ int update_server_record_in_cache(FOREIGN_SERVER *existing,
{ {
DBUG_PRINT("info", ("had a problem inserting server %s at %lx", DBUG_PRINT("info", ("had a problem inserting server %s at %lx",
altered->server_name, (long unsigned int) altered)); altered->server_name, (long unsigned int) altered));
error= 1; error= ER_OUT_OF_RESOURCES;
} }
servers_version++; /* servers updated */
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/* /*
SYNOPSIS SYNOPSIS
...@@ -829,9 +813,9 @@ void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to) ...@@ -829,9 +813,9 @@ void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to)
to->password= strdup_root(&mem, from->password); to->password= strdup_root(&mem, from->password);
if (to->port == -1) if (to->port == -1)
to->port= from->port; to->port= from->port;
if (!to->socket) if (!to->socket && from->socket)
to->socket= strdup_root(&mem, from->socket); to->socket= strdup_root(&mem, from->socket);
if (!to->scheme) if (!to->scheme && from->scheme)
to->scheme= strdup_root(&mem, from->scheme); to->scheme= strdup_root(&mem, from->scheme);
if (!to->owner) if (!to->owner)
to->owner= strdup_root(&mem, from->owner); to->owner= strdup_root(&mem, from->owner);
...@@ -839,6 +823,7 @@ void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to) ...@@ -839,6 +823,7 @@ void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to)
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
/* /*
SYNOPSIS SYNOPSIS
...@@ -861,7 +846,9 @@ void merge_server_struct(FOREIGN_SERVER *from, FOREIGN_SERVER *to) ...@@ -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; int error=0;
DBUG_ENTER("update_server_record"); DBUG_ENTER("update_server_record");
...@@ -876,10 +863,7 @@ int update_server_record(TABLE *table, FOREIGN_SERVER *server) ...@@ -876,10 +863,7 @@ int update_server_record(TABLE *table, FOREIGN_SERVER *server)
HA_READ_KEY_EXACT))) HA_READ_KEY_EXACT)))
{ {
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
{
table->file->print_error(error, MYF(0)); table->file->print_error(error, MYF(0));
error= 1;
}
DBUG_PRINT("info",("server not found!")); DBUG_PRINT("info",("server not found!"));
error= ER_FOREIGN_SERVER_DOESNT_EXIST; error= ER_FOREIGN_SERVER_DOESNT_EXIST;
} }
...@@ -899,6 +883,7 @@ end: ...@@ -899,6 +883,7 @@ end:
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/* /*
SYNOPSIS SYNOPSIS
...@@ -914,11 +899,11 @@ end: ...@@ -914,11 +899,11 @@ end:
*/ */
int delete_server_record(TABLE *table, static int
char *server_name, delete_server_record(TABLE *table,
int server_name_length) char *server_name, int server_name_length)
{ {
int error= 0; int error;
DBUG_ENTER("delete_server_record"); DBUG_ENTER("delete_server_record");
table->use_all_columns(); table->use_all_columns();
...@@ -930,10 +915,7 @@ int delete_server_record(TABLE *table, ...@@ -930,10 +915,7 @@ int delete_server_record(TABLE *table,
HA_READ_KEY_EXACT))) HA_READ_KEY_EXACT)))
{ {
if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE) if (error != HA_ERR_KEY_NOT_FOUND && error != HA_ERR_END_OF_FILE)
{
table->file->print_error(error, MYF(0)); table->file->print_error(error, MYF(0));
error= 1;
}
DBUG_PRINT("info",("server not found!")); DBUG_PRINT("info",("server not found!"));
error= ER_FOREIGN_SERVER_DOESNT_EXIST; error= ER_FOREIGN_SERVER_DOESNT_EXIST;
} }
...@@ -962,28 +944,35 @@ int delete_server_record(TABLE *table, ...@@ -962,28 +944,35 @@ int delete_server_record(TABLE *table,
int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options) int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
{ {
int error; int error= ER_FOREIGN_SERVER_EXISTS;
FOREIGN_SERVER *server; FOREIGN_SERVER *server;
DBUG_ENTER("create_server"); DBUG_ENTER("create_server");
DBUG_PRINT("info", ("server_options->server_name %s", DBUG_PRINT("info", ("server_options->server_name %s",
server_options->server_name)); 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, server= (FOREIGN_SERVER *)alloc_root(&mem,
sizeof(FOREIGN_SERVER)); sizeof(FOREIGN_SERVER));
if ((error= prepare_server_struct_for_insert(server_options, server))) prepare_server_struct_for_insert(server_options, server);
goto end;
if ((error= insert_server(thd, server))) error= insert_server(thd, server);
goto end;
DBUG_PRINT("info", ("error returned %d", error)); DBUG_PRINT("info", ("error returned %d", error));
end: end:
rw_unlock(&THR_LOCK_servers);
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/* /*
SYNOPSIS SYNOPSIS
...@@ -1000,37 +989,44 @@ end: ...@@ -1000,37 +989,44 @@ end:
int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options) int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options)
{ {
int error= 0; int error= ER_FOREIGN_SERVER_DOESNT_EXIST;
FOREIGN_SERVER *altered, *existing; FOREIGN_SERVER *altered, *existing;
LEX_STRING name= { server_options->server_name,
server_options->server_name_length };
DBUG_ENTER("alter_server"); DBUG_ENTER("alter_server");
DBUG_PRINT("info", ("server_options->server_name %s", DBUG_PRINT("info", ("server_options->server_name %s",
server_options->server_name)); 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, altered= (FOREIGN_SERVER *)alloc_root(&mem,
sizeof(FOREIGN_SERVER)); 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, error= update_server(thd, existing, altered);
(byte*) server_options->server_name,
server_options->server_name_length)))
{
error= ER_FOREIGN_SERVER_DOESNT_EXIST;
goto end;
}
if ((error= prepare_server_struct_for_update(server_options, existing, altered))) /* close the servers table before we call closed_cached_connection_tables */
goto end; close_thread_tables(thd);
if ((error= update_server(thd, existing, altered))) if (close_cached_connection_tables(thd, FALSE, &name))
goto end; {
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_UNKNOWN_ERROR, "Server connection in use");
}
end: end:
DBUG_PRINT("info", ("error returned %d", error)); DBUG_PRINT("info", ("error returned %d", error));
VOID(pthread_mutex_unlock(&servers_cache_mutex)); rw_unlock(&THR_LOCK_servers);
DBUG_RETURN(error); DBUG_RETURN(error);
} }
/* /*
SYNOPSIS SYNOPSIS
...@@ -1041,19 +1037,17 @@ end: ...@@ -1041,19 +1037,17 @@ end:
NOTES NOTES
RETURN VALUE RETURN VALUE
0 - no error none
*/ */
int prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, static void
prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options,
FOREIGN_SERVER *server) FOREIGN_SERVER *server)
{ {
int error;
char *unset_ptr= (char*)""; char *unset_ptr= (char*)"";
DBUG_ENTER("prepare_server_struct"); DBUG_ENTER("prepare_server_struct");
error= 0;
/* these two MUST be set */ /* these two MUST be set */
server->server_name= strdup_root(&mem, server_options->server_name); server->server_name= strdup_root(&mem, server_options->server_name);
server->server_name_length= server_options->server_name_length; server->server_name_length= server_options->server_name_length;
...@@ -1083,7 +1077,7 @@ int prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options, ...@@ -1083,7 +1077,7 @@ int prepare_server_struct_for_insert(LEX_SERVER_OPTIONS *server_options,
server->owner= server_options->owner ? server->owner= server_options->owner ?
strdup_root(&mem, server_options->owner) : unset_ptr; 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, ...@@ -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, static void
prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
FOREIGN_SERVER *existing, FOREIGN_SERVER *existing,
FOREIGN_SERVER *altered) FOREIGN_SERVER *altered)
{ {
int error;
DBUG_ENTER("prepare_server_struct_for_update"); DBUG_ENTER("prepare_server_struct_for_update");
error= 0;
altered->server_name= strdup_root(&mem, server_options->server_name); altered->server_name= strdup_root(&mem, server_options->server_name);
altered->server_name_length= server_options->server_name_length; altered->server_name_length= server_options->server_name_length;
...@@ -1156,7 +1149,7 @@ int prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options, ...@@ -1156,7 +1149,7 @@ int prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
(strcmp(server_options->owner, existing->owner))) ? (strcmp(server_options->owner, existing->owner))) ?
strdup_root(&mem, server_options->owner) : 0; 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, ...@@ -1175,16 +1168,65 @@ int prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
void servers_free(bool end) void servers_free(bool end)
{ {
DBUG_ENTER("servers_free"); DBUG_ENTER("servers_free");
if (!servers_cache_initialised) if (!hash_inited(&servers_cache))
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
VOID(pthread_mutex_destroy(&servers_cache_mutex)); if (!end)
servers_cache_initialised=0; {
free_root(&mem, MYF(MY_MARK_BLOCKS_FREE));
my_hash_reset(&servers_cache);
DBUG_VOID_RETURN;
}
rwlock_destroy(&THR_LOCK_servers);
free_root(&mem,MYF(0)); free_root(&mem,MYF(0));
hash_free(&servers_cache); hash_free(&servers_cache);
DBUG_VOID_RETURN; 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) ...@@ -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; uint server_name_length;
FOREIGN_SERVER *server= 0; FOREIGN_SERVER *server;
DBUG_ENTER("get_server_by_name"); DBUG_ENTER("get_server_by_name");
DBUG_PRINT("info", ("server_name %s", server_name)); DBUG_PRINT("info", ("server_name %s", server_name));
...@@ -1212,12 +1254,11 @@ FOREIGN_SERVER *get_server_by_name(const char *server_name) ...@@ -1212,12 +1254,11 @@ FOREIGN_SERVER *get_server_by_name(const char *server_name)
if (! server_name || !strlen(server_name)) if (! server_name || !strlen(server_name))
{ {
DBUG_PRINT("info", ("server_name not defined!")); DBUG_PRINT("info", ("server_name not defined!"));
error_num= 1;
DBUG_RETURN((FOREIGN_SERVER *)NULL); DBUG_RETURN((FOREIGN_SERVER *)NULL);
} }
DBUG_PRINT("info", ("locking servers_cache")); 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, if (!(server= (FOREIGN_SERVER *) hash_search(&servers_cache,
(byte*) server_name, (byte*) server_name,
server_name_length))) server_name_length)))
...@@ -1226,8 +1267,12 @@ FOREIGN_SERVER *get_server_by_name(const char *server_name) ...@@ -1226,8 +1267,12 @@ FOREIGN_SERVER *get_server_by_name(const char *server_name)
server_name, server_name_length)); server_name, server_name_length));
server= (FOREIGN_SERVER *) NULL; server= (FOREIGN_SERVER *) NULL;
} }
/* otherwise, make copy of server */
else
server= clone_server(mem, server, buff);
DBUG_PRINT("info", ("unlocking servers_cache")); DBUG_PRINT("info", ("unlocking servers_cache"));
VOID(pthread_mutex_unlock(&servers_cache_mutex)); rw_unlock(&THR_LOCK_servers);
DBUG_RETURN(server); DBUG_RETURN(server);
} }
...@@ -25,40 +25,19 @@ typedef struct st_federated_server ...@@ -25,40 +25,19 @@ typedef struct st_federated_server
} FOREIGN_SERVER; } FOREIGN_SERVER;
/* cache handlers */ /* cache handlers */
my_bool servers_init(bool dont_read_server_table); bool servers_init(bool dont_read_server_table);
my_bool servers_reload(THD *thd); bool servers_reload(THD *thd);
my_bool get_server_from_table_to_cache(TABLE *table);
void servers_free(bool end=0); void servers_free(bool end=0);
/* insert functions */ /* insert functions */
int create_server(THD *thd, LEX_SERVER_OPTIONS *server_options); 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 */ /* drop functions */
int drop_server(THD *thd, LEX_SERVER_OPTIONS *server_options); 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 */ /* update functions */
int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options); int alter_server(THD *thd, LEX_SERVER_OPTIONS *server_options);
int prepare_server_struct_for_update(LEX_SERVER_OPTIONS *server_options,
FOREIGN_SERVER *existing, /* lookup functions */
FOREIGN_SERVER *altered); FOREIGN_SERVER *get_server_by_name(MEM_ROOT *mem, const char *server_name,
int update_server(THD *thd, FOREIGN_SERVER *existing, FOREIGN_SERVER *altered); FOREIGN_SERVER *server_buffer);
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);
...@@ -43,23 +43,55 @@ ...@@ -43,23 +43,55 @@
The create table will simply create the .frm file, and within the The create table will simply create the .frm file, and within the
"CREATE TABLE" SQL, there SHALL be any of the following : "CREATE TABLE" SQL, there SHALL be any of the following :
comment=scheme://username:password@hostname:port/database/tablename connection=scheme://username:password@hostname:port/database/tablename
comment=scheme://username@hostname/database/tablename connection=scheme://username@hostname/database/tablename
comment=scheme://username:password@hostname/database/tablename connection=scheme://username:password@hostname/database/tablename
comment=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: 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
CONNECTION="mysql://root@127.0.0.1:3306/db1/t1"
This is a first release, conceptual release Then, we can also change the server to point to a new schema:
Only 'mysql://' is supported at this release.
ALTER SERVER 'server_one' options(DATABASE 'db2');
This comment connection string is necessary for the handler to be All subsequent calls will now be against db2.t1! Guess what? You don't
able to connect to the foreign server. 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: The basic flow is this:
...@@ -166,7 +198,7 @@ ...@@ -166,7 +198,7 @@
KEY other_key (other)) KEY other_key (other))
ENGINE="FEDERATED" ENGINE="FEDERATED"
DEFAULT CHARSET=latin1 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 Notice the "COMMENT" and "ENGINE" field? This is where you
respectively set the engine type, "FEDERATED" and foreign respectively set the engine type, "FEDERATED" and foreign
...@@ -263,7 +295,7 @@ ...@@ -263,7 +295,7 @@
To run these tests, go into ./mysql-test (based in the directory you To run these tests, go into ./mysql-test (based in the directory you
built the server in) 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: To run the test, or if you want to run the test and have debug info:
...@@ -311,7 +343,7 @@ ...@@ -311,7 +343,7 @@
------------- -------------
These were the files that were modified or created for this These were the files that were modified or created for this
Federated handler to work: Federated handler to work, in 5.0:
./configure.in ./configure.in
./sql/Makefile.am ./sql/Makefile.am
...@@ -329,6 +361,13 @@ ...@@ -329,6 +361,13 @@
./sql/ha_federated.cc ./sql/ha_federated.cc
./sql/ha_federated.h ./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) ...@@ -546,42 +585,39 @@ static int parse_url_error(FEDERATED_SHARE *share, TABLE *table, int error_num)
int buf_len; int buf_len;
DBUG_ENTER("ha_federated parse_url_error"); 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, buf_len= min(table->s->connect_string.length,
FEDERATED_QUERY_BUFFER_SIZE-1); FEDERATED_QUERY_BUFFER_SIZE-1);
strmake(buf, table->s->connect_string.str, buf_len); strmake(buf, table->s->connect_string.str, buf_len);
my_error(error_num, MYF(0), buf); my_error(error_num, MYF(0), buf);
DBUG_RETURN(error_num); DBUG_RETURN(error_num);
} }
/* /*
retrieve server object which contains server meta-data retrieve server object which contains server meta-data
from the system table given a server's name, set share from the system table given a server's name, set share
connection parameter members 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; int error_num= ER_FOREIGN_SERVER_DOESNT_EXIST;
char error_buffer[FEDERATED_QUERY_BUFFER_SIZE]; char error_buffer[FEDERATED_QUERY_BUFFER_SIZE];
FOREIGN_SERVER *server; FOREIGN_SERVER *server, server_buffer;
DBUG_ENTER("ha_federated::get_connection"); 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= 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!")); DBUG_PRINT("info", ("get_server_by_name returned > 0 error condition!"));
/* need to come up with error handling */ /* need to come up with error handling */
error_num=1; error_num=1;
goto error; 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 Most of these should never be empty strings, error handling will
...@@ -590,29 +626,22 @@ int get_connection(FEDERATED_SHARE *share) ...@@ -590,29 +626,22 @@ int get_connection(FEDERATED_SHARE *share)
except there are errors in the trace file of the share being overrun except there are errors in the trace file of the share being overrun
at the address of the share. at the address of the share.
*/ */
if (server->server_name) share->server_name_length= server->server_name_length;
share->server_name= 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; share->username= server->username;
if (server->password)
share->password= server->password; share->password= server->password;
if (server->db)
share->database= server->db; share->database= server->db;
#ifndef I_AM_PARANOID
share->port= server->port ? (ushort) server->port : MYSQL_PORT; share->port= server->port > 0 && server->port < 65536 ?
#else
if (server->host) share->port= server->port > 1023 && server->port < 65536 ?
#endif
(ushort) server->port : MYSQL_PORT;
share->hostname= server->host; share->hostname= server->host;
if (server->socket) if (!(share->socket= server->socket) &&
share->socket= server->socket; !strcmp(share->hostname, my_localhost))
else if (strcmp(share->hostname, my_localhost) == 0) share->socket= (char *) MYSQL_UNIX_ADDR;
share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0));
if (server->scheme)
share->scheme= server->scheme; share->scheme= server->scheme;
else
share->scheme= NULL;
DBUG_PRINT("info", ("share->username %s", share->username)); DBUG_PRINT("info", ("share->username %s", share->username));
DBUG_PRINT("info", ("share->password %s", share->password)); DBUG_PRINT("info", ("share->password %s", share->password));
...@@ -635,6 +664,7 @@ error: ...@@ -635,6 +664,7 @@ error:
SYNOPSIS SYNOPSIS
parse_url() parse_url()
mem_root MEM_ROOT pointer for memory allocation
share pointer to FEDERATED share share pointer to FEDERATED share
table pointer to current TABLE class table pointer to current TABLE class
table_create_flag determines what error to throw table_create_flag determines what error to throw
...@@ -684,7 +714,7 @@ error: ...@@ -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 table_create_flag)
{ {
uint error_num= (table_create_flag ? uint error_num= (table_create_flag ?
...@@ -698,20 +728,19 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, ...@@ -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", ("Length: %d", table->s->connect_string.length));
DBUG_PRINT("info", ("String: '%.*s'", table->s->connect_string.length, DBUG_PRINT("info", ("String: '%.*s'", table->s->connect_string.length,
table->s->connect_string.str)); table->s->connect_string.str));
share->connection_string= my_strndup(table->s->connect_string.str, share->connection_string= strmake_root(mem_root, table->s->connect_string.str,
table->s->connect_string.length, table->s->connect_string.length);
MYF(0));
// 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", DBUG_PRINT("info",("parse_url alloced share->connection_string %lx",
(long unsigned int) share->connection_string)); (long unsigned int) share->connection_string));
DBUG_PRINT("info",("share->connection_string %s",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, '/')) && No :// or @ in connection string. Must be a straight connection name of
(!strchr(share->connection_string, '@')) && either "servername" or "servername/tablename"
(!strchr(share->connection_string, ';'))) */
if ( (!strstr(share->connection_string, "://") &&
(!strchr(share->connection_string, '@'))))
{ {
DBUG_PRINT("info", DBUG_PRINT("info",
...@@ -720,17 +749,51 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, ...@@ -720,17 +749,51 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table,
share->connection_string, share->connection_string,
(long unsigned int) share->connection_string)); (long unsigned int) share->connection_string));
/* ok, so we do a little parsing, but not completely! */
share->parsed= FALSE; share->parsed= FALSE;
if ((error_num= get_connection(share))) /*
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; goto error;
}
/*
otherwise, straight server name, use tablename of federated table
as remote table name
*/
else
{
/* /*
connection specifies everything but, resort to connection specifies everything but, resort to
expecting remote and foreign table names to match expecting remote and foreign table names to match
*/ */
share->table_name= table->s->table_name.str; share->table_name= strmake_root(mem_root, table->s->table_name.str,
share->table_name_length= table->s->table_name.length; (share->table_name_length= table->s->table_name.length));
share->table_name[share->table_name_length]= '\0'; 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 else
{ {
...@@ -816,7 +879,7 @@ Then password is a null string, so set to NULL ...@@ -816,7 +879,7 @@ Then password is a null string, so set to NULL
if (!share->port) if (!share->port)
{ {
if (strcmp(share->hostname, my_localhost) == 0) if (strcmp(share->hostname, my_localhost) == 0)
share->socket= my_strdup(MYSQL_UNIX_ADDR, MYF(0)); share->socket= (char *) MYSQL_UNIX_ADDR;
else else
share->port= MYSQL_PORT; share->port= MYSQL_PORT;
} }
...@@ -1420,22 +1483,26 @@ err: ...@@ -1420,22 +1483,26 @@ err:
static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
{ {
char *select_query;
char query_buffer[FEDERATED_QUERY_BUFFER_SIZE]; char query_buffer[FEDERATED_QUERY_BUFFER_SIZE];
Field **field; Field **field;
String query(query_buffer, sizeof(query_buffer), &my_charset_bin); String query(query_buffer, sizeof(query_buffer), &my_charset_bin);
FEDERATED_SHARE *share= NULL, tmp_share; 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, In order to use this string, we must first zero it's length,
or it will contain garbage or it will contain garbage
*/ */
query.length(0); query.length(0);
init_alloc_root(&mem_root, 256, 0);
pthread_mutex_lock(&federated_mutex); pthread_mutex_lock(&federated_mutex);
tmp_share.share_key= table_name; tmp_share.share_key= table_name;
tmp_share.share_key_length= strlen(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; goto error;
/* TODO: change tmp_share.scheme to LEX_STRING object */ /* TODO: change tmp_share.scheme to LEX_STRING object */
...@@ -1456,24 +1523,17 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) ...@@ -1456,24 +1523,17 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
query.length(query.length() - sizeof_trailing_comma); query.length(query.length() - sizeof_trailing_comma);
query.append(STRING_WITH_LEN(" FROM `")); 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 *) if (!(share= (FEDERATED_SHARE *) memdup_root(&mem_root, (char*)&tmp_share, sizeof(*share))) ||
my_multi_malloc(MYF(MY_WME), !(share->select_query= (char*) strmake_root(&mem_root, query.ptr(), query.length())))
&share, sizeof(*share),
&select_query,
query.length()+table->s->connect_string.length+1,
NullS)))
goto error; 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->use_count= 0;
share->mem_root= mem_root;
DBUG_PRINT("info", DBUG_PRINT("info",
("share->select_query %s", share->select_query)); ("share->select_query %s", share->select_query));
...@@ -1482,17 +1542,18 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) ...@@ -1482,17 +1542,18 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
thr_lock_init(&share->lock); thr_lock_init(&share->lock);
pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST); pthread_mutex_init(&share->mutex, MY_MUTEX_INIT_FAST);
} }
else
free_root(&mem_root, MYF(0)); /* prevents memory leak */
share->use_count++; share->use_count++;
pthread_mutex_unlock(&federated_mutex); pthread_mutex_unlock(&federated_mutex);
return share; DBUG_RETURN(share);
error: error:
pthread_mutex_unlock(&federated_mutex); pthread_mutex_unlock(&federated_mutex);
my_free((gptr) tmp_share.connection_string, MYF(MY_ALLOW_ZERO_PTR)); free_root(&mem_root, MYF(0));
tmp_share.connection_string= 0; DBUG_RETURN(NULL);
my_free((gptr) share, MYF(MY_ALLOW_ZERO_PTR));
return NULL;
} }
...@@ -1504,23 +1565,16 @@ error: ...@@ -1504,23 +1565,16 @@ error:
static int free_share(FEDERATED_SHARE *share) static int free_share(FEDERATED_SHARE *share)
{ {
MEM_ROOT mem_root= share->mem_root;
DBUG_ENTER("free_share"); DBUG_ENTER("free_share");
pthread_mutex_lock(&federated_mutex); pthread_mutex_lock(&federated_mutex);
if (!--share->use_count) if (!--share->use_count)
{ {
hash_delete(&federated_open_tables, (byte*) share); 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); thr_lock_delete(&share->lock);
VOID(pthread_mutex_destroy(&share->mutex)); VOID(pthread_mutex_destroy(&share->mutex));
my_free((gptr) share, MYF(0)); free_root(&mem_root, MYF(0));
} }
pthread_mutex_unlock(&federated_mutex); pthread_mutex_unlock(&federated_mutex);
...@@ -1589,6 +1643,8 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) ...@@ -1589,6 +1643,8 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
mysql_options(mysql,MYSQL_SET_CHARSET_NAME, mysql_options(mysql,MYSQL_SET_CHARSET_NAME,
this->table->s->table_charset->csname); 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, if (!mysql || !mysql_real_connect(mysql,
share->hostname, share->hostname,
share->username, share->username,
...@@ -2831,15 +2887,13 @@ int ha_federated::create(const char *name, TABLE *table_arg, ...@@ -2831,15 +2887,13 @@ int ha_federated::create(const char *name, TABLE *table_arg,
HA_CREATE_INFO *create_info) HA_CREATE_INFO *create_info)
{ {
int retval; int retval;
THD *thd= current_thd;
FEDERATED_SHARE tmp_share; // Only a temporary share, to test the url FEDERATED_SHARE tmp_share; // Only a temporary share, to test the url
DBUG_ENTER("ha_federated::create"); 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); 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); DBUG_RETURN(retval);
} }
......
...@@ -43,6 +43,8 @@ ...@@ -43,6 +43,8 @@
The example implements the minimum of what you will probably need. The example implements the minimum of what you will probably need.
*/ */
typedef struct st_federated_share { typedef struct st_federated_share {
MEM_ROOT mem_root;
bool parsed; bool parsed;
/* this key is unique db/tablename */ /* this key is unique db/tablename */
const char *share_key; const char *share_key;
...@@ -67,6 +69,7 @@ typedef struct st_federated_share { ...@@ -67,6 +69,7 @@ typedef struct st_federated_share {
char *sport; char *sport;
int share_key_length; int share_key_length;
ushort port; ushort port;
uint table_name_length, server_name_length, connect_string_length, use_count; uint table_name_length, server_name_length, connect_string_length, use_count;
pthread_mutex_t mutex; pthread_mutex_t mutex;
THR_LOCK lock; THR_LOCK lock;
......
...@@ -628,6 +628,9 @@ int ha_heap::create(const char *name, TABLE *table_arg, ...@@ -628,6 +628,9 @@ int ha_heap::create(const char *name, TABLE *table_arg,
seg->length= (uint) key_part->length; seg->length= (uint) key_part->length;
seg->flag= key_part->key_part_flag; seg->flag= key_part->key_part_flag;
if (field->flags & (ENUM_FLAG | SET_FLAG))
seg->charset= &my_charset_bin;
else
seg->charset= field->charset(); seg->charset= field->charset();
if (field->null_ptr) if (field->null_ptr)
{ {
......
...@@ -105,7 +105,6 @@ int hp_rb_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *record, ...@@ -105,7 +105,6 @@ int hp_rb_write_key(HP_INFO *info, HP_KEYDEF *keyinfo, const byte *record,
heap_rb_param custom_arg; heap_rb_param custom_arg;
uint old_allocated; uint old_allocated;
info->last_pos= NULL; /* For heap_rnext/heap_rprev */
custom_arg.keyseg= keyinfo->seg; custom_arg.keyseg= keyinfo->seg;
custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos); custom_arg.key_length= hp_rb_make_key(keyinfo, info->recbuf, record, recpos);
if (keyinfo->flag & HA_NOSAME) if (keyinfo->flag & HA_NOSAME)
......
...@@ -635,6 +635,9 @@ bool ha_myisam::check_if_locking_is_allowed(uint sql_command, ...@@ -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) int ha_myisam::open(const char *name, int mode, uint test_if_locked)
{ {
MI_KEYDEF *keyinfo;
MI_COLUMNDEF *recinfo= 0;
uint recs;
uint i; uint i;
/* /*
...@@ -657,6 +660,26 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked) ...@@ -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))) if (!(file=mi_open(name, mode, test_if_locked | HA_OPEN_FROM_SQL_LAYER)))
return (my_errno ? my_errno : -1); 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)) if (test_if_locked & (HA_OPEN_IGNORE_IF_LOCKED | HA_OPEN_TMP_TABLE))
VOID(mi_extra(file, HA_EXTRA_NO_WAIT_LOCK, 0)); 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) ...@@ -677,7 +700,18 @@ int ha_myisam::open(const char *name, int mode, uint test_if_locked)
(struct st_mysql_ftparser *)parser->plugin->info; (struct st_mysql_ftparser *)parser->plugin->info;
table->key_info[i].block_size= file->s->keyinfo[i].block_length; 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) int ha_myisam::close(void)
...@@ -1023,6 +1057,22 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize) ...@@ -1023,6 +1057,22 @@ int ha_myisam::repair(THD *thd, MI_CHECK &param, bool do_optimize)
ha_rows rows= file->state->records; ha_rows rows= file->state->records;
DBUG_ENTER("ha_myisam::repair"); 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.db_name= table->s->db.str;
param.table_name= table->alias; param.table_name= table->alias;
param.tmpfile_createflag = O_RDWR | O_TRUNC; param.tmpfile_createflag = O_RDWR | O_TRUNC;
......
...@@ -573,6 +573,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ...@@ -573,6 +573,10 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
pthread_mutex_lock(&THR_LOCK_myisam); 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) if (ci->index_file_name)
{ {
char *iext= strrchr(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, ...@@ -584,13 +588,14 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
if ((path= strrchr(ci->index_file_name, FN_LIBCHAR))) if ((path= strrchr(ci->index_file_name, FN_LIBCHAR)))
*path= '\0'; *path= '\0';
fn_format(filename, name, ci->index_file_name, MI_NAME_IEXT, 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 else
{ {
fn_format(filename, ci->index_file_name, "", MI_NAME_IEXT, fn_format(filename, ci->index_file_name, "", MI_NAME_IEXT,
MY_UNPACK_FILENAME | (have_iext ? MY_REPLACE_EXT : MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
MY_APPEND_EXT)); (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
} }
fn_format(linkname, name, "", MI_NAME_IEXT, fn_format(linkname, name, "", MI_NAME_IEXT,
MY_UNPACK_FILENAME|MY_APPEND_EXT); MY_UNPACK_FILENAME|MY_APPEND_EXT);
...@@ -603,10 +608,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ...@@ -603,10 +608,11 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs,
} }
else else
{ {
char *iext= strrchr(name, '.');
int have_iext= iext && !strcmp(iext, MI_NAME_IEXT);
fn_format(filename, name, "", MI_NAME_IEXT, fn_format(filename, name, "", MI_NAME_IEXT,
(MY_UNPACK_FILENAME | MY_UNPACK_FILENAME | MY_RETURN_REAL_PATH |
(flags & HA_DONT_TOUCH_DATA) ? MY_RETURN_REAL_PATH : 0) | (have_iext ? MY_REPLACE_EXT : MY_APPEND_EXT));
MY_APPEND_EXT);
linkname_ptr=0; linkname_ptr=0;
/* Replace the current file */ /* Replace the current file */
create_flag=MY_DELETE_OLD; create_flag=MY_DELETE_OLD;
...@@ -618,6 +624,9 @@ int mi_create(const char *name,uint keys,MI_KEYDEF *keydefs, ...@@ -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 A TRUNCATE command checks for the table in the cache only and could
be fooled to believe, the table is not open. be fooled to believe, the table is not open.
Pull the emergency brake in this situation. (Bug #8306) 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)) if (test_if_reopen(filename))
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment