Merge chilla.local:/home/mydev/mysql-5.1-amerge
into chilla.local:/home/mydev/mysql-5.1-aid
This commit is contained in:
commit
69bf342a20
@ -1558,6 +1558,8 @@ id
|
||||
3
|
||||
4
|
||||
5
|
||||
DROP TABLE federated.t1;
|
||||
DROP TABLE federated.t1;
|
||||
DROP TABLE IF EXISTS federated.bug_17377_table;
|
||||
CREATE TABLE federated.bug_17377_table (
|
||||
`fld_cid` bigint(20) NOT NULL auto_increment,
|
||||
@ -1601,7 +1603,92 @@ fld_cid fld_name fld_parentid fld_delt
|
||||
5 Torkel 0 0
|
||||
DROP TABLE federated.t1;
|
||||
DROP TABLE federated.bug_17377_table;
|
||||
DROP TABLE federated.t1;
|
||||
create table federated.t1 (i1 int, i2 int, i3 int);
|
||||
create table federated.t2 (id int, c1 varchar(20), c2 varchar(20));
|
||||
create table federated.t1 (i1 int, i2 int, i3 int) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
|
||||
create table federated.t2 (id int, c1 varchar(20), c2 varchar(20)) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t2';
|
||||
insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
|
||||
insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
|
||||
select * from federated.t1 order by i1;
|
||||
i1 i2 i3
|
||||
1 5 10
|
||||
2 2 2
|
||||
3 7 12
|
||||
4 5 2
|
||||
9 10 15
|
||||
select * from federated.t2;
|
||||
id c1 c2
|
||||
9 abc def
|
||||
5 opq lmn
|
||||
2 test t t test
|
||||
update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
|
||||
select * from federated.t1 order by i1;
|
||||
i1 i2 i3
|
||||
1 5 10
|
||||
2 15 2
|
||||
3 7 12
|
||||
4 5 2
|
||||
9 15 15
|
||||
select * from federated.t2 order by id;
|
||||
id c1 c2
|
||||
2 test t ppc
|
||||
5 opq lmn
|
||||
9 abc ppc
|
||||
delete federated.t1.*,federated.t2.* from federated.t1,federated.t2 where t1.i2=t2.id;
|
||||
select * from federated.t1 order by i1;
|
||||
i1 i2 i3
|
||||
2 15 2
|
||||
3 7 12
|
||||
9 15 15
|
||||
select * from federated.t2 order by id;
|
||||
id c1 c2
|
||||
2 test t ppc
|
||||
9 abc ppc
|
||||
drop table federated.t1, federated.t2;
|
||||
drop table federated.t1, federated.t2;
|
||||
create table federated.t1 (i1 int, i2 int, i3 int, primary key (i1));
|
||||
create table federated.t2 (id int, c1 varchar(20), c2 varchar(20), primary key (id));
|
||||
create table federated.t1 (i1 int auto_increment not null, i2 int, i3 int, primary key (i1)) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t1';
|
||||
create table federated.t2 (id int auto_increment not null, c1 varchar(20), c2 varchar(20), primary key(id)) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:SLAVE_PORT/federated/t2';
|
||||
insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
|
||||
insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
|
||||
select * from federated.t1 order by i1;
|
||||
i1 i2 i3
|
||||
1 5 10
|
||||
2 2 2
|
||||
3 7 12
|
||||
4 5 2
|
||||
9 10 15
|
||||
select * from federated.t2 order by id;
|
||||
id c1 c2
|
||||
2 test t t test
|
||||
5 opq lmn
|
||||
9 abc def
|
||||
update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
|
||||
select * from federated.t1 order by i1;
|
||||
i1 i2 i3
|
||||
1 5 10
|
||||
2 15 2
|
||||
3 7 12
|
||||
4 5 2
|
||||
9 15 15
|
||||
select * from federated.t2 order by id;
|
||||
id c1 c2
|
||||
2 test t ppc
|
||||
5 opq lmn
|
||||
9 abc ppc
|
||||
delete federated.t1.*,federated.t2.* from federated.t1,federated.t2 where t1.i2=t2.id;
|
||||
select * from federated.t1 order by i1;
|
||||
i1 i2 i3
|
||||
2 15 2
|
||||
3 7 12
|
||||
9 15 15
|
||||
select * from federated.t2 order by id;
|
||||
id c1 c2
|
||||
2 test t ppc
|
||||
9 abc ppc
|
||||
drop table federated.t1, federated.t2;
|
||||
drop table federated.t1, federated.t2;
|
||||
DROP TABLE IF EXISTS federated.t1;
|
||||
DROP DATABASE IF EXISTS federated;
|
||||
DROP TABLE IF EXISTS federated.t1;
|
||||
|
@ -1256,6 +1256,10 @@ SELECT LAST_INSERT_ID();
|
||||
INSERT INTO federated.t1 VALUES ();
|
||||
SELECT LAST_INSERT_ID();
|
||||
SELECT * FROM federated.t1;
|
||||
DROP TABLE federated.t1;
|
||||
|
||||
connection slave;
|
||||
DROP TABLE federated.t1;
|
||||
|
||||
#
|
||||
# Bug#17377 Federated Engine returns wrong Data, always the rows
|
||||
@ -1310,19 +1314,19 @@ select * from federated.t1 where fld_parentid=0 and fld_delt=0;
|
||||
DROP TABLE federated.t1;
|
||||
connection slave;
|
||||
DROP TABLE federated.bug_17377_table;
|
||||
DROP TABLE federated.t1;
|
||||
|
||||
#
|
||||
# Test multi updates and deletes without keys
|
||||
# BUG 19773 Crash when using multi-table updates, deletes
|
||||
# with federated tables
|
||||
#
|
||||
|
||||
# The following can be enabled when bug #19773 has been fixed
|
||||
--disable_parsing
|
||||
connection slave;
|
||||
create table federated.t1 (i1 int, i2 int, i3 int);
|
||||
create table federated.t2 (id int, c1 varchar(20), c2 varchar(20));
|
||||
|
||||
connection master;
|
||||
--replace_result $SLAVE_MYPORT SLAVE_PORT
|
||||
eval create table federated.t1 (i1 int, i2 int, i3 int) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
|
||||
--replace_result $SLAVE_MYPORT SLAVE_PORT
|
||||
eval create table federated.t2 (id int, c1 varchar(20), c2 varchar(20)) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t2';
|
||||
insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
|
||||
insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
|
||||
@ -1331,22 +1335,23 @@ select * from federated.t2;
|
||||
update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
|
||||
select * from federated.t1 order by i1;
|
||||
select * from federated.t2 order by id;
|
||||
delete t1.*,t2.* from federated.t1,federated.t2 where t1.i2=t2.id;
|
||||
delete federated.t1.*,federated.t2.* from federated.t1,federated.t2 where t1.i2=t2.id;
|
||||
select * from federated.t1 order by i1;
|
||||
select * from federated.t2 order by id;
|
||||
drop table federated.t1, federated.t2;
|
||||
connection slave;
|
||||
drop table federated.t1, federated.t2;
|
||||
connection master;
|
||||
|
||||
# Test multi updates and deletes with keys
|
||||
|
||||
connection slave;
|
||||
create table federated.t1 (i1 int, i2 int, i3 int, primary key (i1));
|
||||
create table federated.t2 (id int, c1 varchar(20), c2 varchar(20), primary key (id));
|
||||
|
||||
connection master;
|
||||
eval create table federated.t1 (i1 int auto_increment not null, i2 int, i3 int, primary key (i1)) ENGINE=FEDERATED ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
|
||||
eval create table federated.t2 (id int auto_increment not null, c1 varchar(20), c2 varchar(20), primary key(id)) ENGINE=FEDERATED ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t2';
|
||||
--replace_result $SLAVE_MYPORT SLAVE_PORT
|
||||
eval create table federated.t1 (i1 int auto_increment not null, i2 int, i3 int, primary key (i1)) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t1';
|
||||
--replace_result $SLAVE_MYPORT SLAVE_PORT
|
||||
eval create table federated.t2 (id int auto_increment not null, c1 varchar(20), c2 varchar(20), primary key(id)) ENGINE=FEDERATED CONNECTION='mysql://root@127.0.0.1:$SLAVE_MYPORT/federated/t2';
|
||||
insert into federated.t1 values (1,5,10),(3,7,12),(4,5,2),(9,10,15),(2,2,2);
|
||||
insert into federated.t2 values (9,"abc","def"),(5,"opq","lmn"),(2,"test t","t test");
|
||||
select * from federated.t1 order by i1;
|
||||
@ -1354,13 +1359,12 @@ select * from federated.t2 order by id;
|
||||
update federated.t1,federated.t2 set t1.i2=15, t2.c2="ppc" where t1.i1=t2.id;
|
||||
select * from federated.t1 order by i1;
|
||||
select * from federated.t2 order by id;
|
||||
delete t1.*,t2.* from federated.t1,federated.t2 where t1.i2=t2.id;
|
||||
delete federated.t1.*,federated.t2.* from federated.t1,federated.t2 where t1.i2=t2.id;
|
||||
select * from federated.t1 order by i1;
|
||||
select * from federated.t2 order by id;
|
||||
drop table federated.t1, federated.t2;
|
||||
|
||||
connection slave;
|
||||
drop table federated.t1, federated.t2;
|
||||
connection master;
|
||||
--enable_parsing
|
||||
|
||||
--source include/federated_cleanup.inc
|
||||
source include/federated_cleanup.inc;
|
||||
|
@ -32,13 +32,14 @@
|
||||
so to read, that data has to be parsed into fields, to write, fields have to
|
||||
be stored in this format to write to this data file.
|
||||
|
||||
With MySQL Federated storage engine, there will be no local files for each
|
||||
table's data (such as .MYD). A foreign database will store the data that would
|
||||
normally be in this file. This will necessitate the use of MySQL client API
|
||||
to read, delete, update, insert this data. The data will have to be retrieve
|
||||
via an SQL call "SELECT * FROM users". Then, to read this data, it will have
|
||||
to be retrieved via mysql_fetch_row one row at a time, then converted from
|
||||
the column in this select into the format that the handler expects.
|
||||
With MySQL Federated storage engine, there will be no local files
|
||||
for each table's data (such as .MYD). A foreign database will store
|
||||
the data that would normally be in this file. This will necessitate
|
||||
the use of MySQL client API to read, delete, update, insert this
|
||||
data. The data will have to be retrieve via an SQL call "SELECT *
|
||||
FROM users". Then, to read this data, it will have to be retrieved
|
||||
via mysql_fetch_row one row at a time, then converted from the
|
||||
column in this select into the format that the handler expects.
|
||||
|
||||
The create table will simply create the .frm file, and within the
|
||||
"CREATE TABLE" SQL, there SHALL be any of the following :
|
||||
@ -385,8 +386,8 @@ static handler *federated_create_handler(TABLE_SHARE *table,
|
||||
static byte *federated_get_key(FEDERATED_SHARE *share, uint *length,
|
||||
my_bool not_used __attribute__ ((unused)))
|
||||
{
|
||||
*length= share->table_name_length;
|
||||
return (byte*) share->table_name;
|
||||
*length= share->connect_string_length;
|
||||
return (byte*) share->scheme;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -415,7 +416,7 @@ int federated_db_init()
|
||||
|
||||
if (pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST))
|
||||
goto error;
|
||||
if (!hash_init(&federated_open_tables, system_charset_info, 32, 0, 0,
|
||||
if (!hash_init(&federated_open_tables, &my_charset_bin, 32, 0, 0,
|
||||
(hash_get_key) federated_get_key, 0, 0))
|
||||
{
|
||||
federated_init= TRUE;
|
||||
@ -510,6 +511,7 @@ static int check_foreign_data_source(FEDERATED_SHARE *share,
|
||||
}
|
||||
else
|
||||
{
|
||||
int escaped_table_name_length= 0;
|
||||
/*
|
||||
Since we do not support transactions at this version, we can let the
|
||||
client API silently reconnect. For future versions, we will need more
|
||||
@ -528,17 +530,16 @@ static int check_foreign_data_source(FEDERATED_SHARE *share,
|
||||
query.append(FEDERATED_STAR);
|
||||
query.append(FEDERATED_FROM);
|
||||
query.append(FEDERATED_BTICK);
|
||||
escape_string_for_mysql(&my_charset_bin, (char *)escaped_table_name,
|
||||
escaped_table_name_length=
|
||||
escape_string_for_mysql(&my_charset_bin, (char*)escaped_table_name,
|
||||
sizeof(escaped_table_name),
|
||||
share->table_name,
|
||||
share->table_name_length);
|
||||
query.append(escaped_table_name);
|
||||
query.append(escaped_table_name, escaped_table_name_length);
|
||||
query.append(FEDERATED_BTICK);
|
||||
query.append(FEDERATED_WHERE);
|
||||
query.append(FEDERATED_FALSE);
|
||||
|
||||
DBUG_PRINT("info", ("check_foreign_data_source query %s",
|
||||
query.c_ptr_quick()));
|
||||
if (mysql_real_query(mysql, query.ptr(), query.length()))
|
||||
{
|
||||
error_code= table_create_flag ?
|
||||
@ -632,8 +633,7 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table,
|
||||
share->scheme= my_strndup(table->s->connect_string.str,
|
||||
table->s->connect_string.length, MYF(0));
|
||||
|
||||
// Add a null for later termination of table name
|
||||
share->scheme[table->s->connect_string.length]= 0;
|
||||
share->connect_string_length= table->s->connect_string.length;
|
||||
DBUG_PRINT("info",("parse_url alloced share->scheme %lx", share->scheme));
|
||||
|
||||
/*
|
||||
@ -699,7 +699,7 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table,
|
||||
share->table_name++;
|
||||
|
||||
share->table_name_length= strlen(share->table_name);
|
||||
|
||||
|
||||
/* make sure there's not an extra / */
|
||||
if ((strchr(share->table_name, '/')))
|
||||
goto error;
|
||||
@ -735,8 +735,7 @@ error:
|
||||
|
||||
ha_federated::ha_federated(TABLE_SHARE *table_arg)
|
||||
:handler(&federated_hton, table_arg),
|
||||
mysql(0), stored_result(0),
|
||||
ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0)
|
||||
mysql(0), stored_result(0)
|
||||
{
|
||||
trx_next= 0;
|
||||
}
|
||||
@ -747,8 +746,9 @@ ha_federated::ha_federated(TABLE_SHARE *table_arg)
|
||||
|
||||
SYNOPSIS
|
||||
convert_row_to_internal_format()
|
||||
record Byte pointer to record
|
||||
row MySQL result set row from fetchrow()
|
||||
record Byte pointer to record
|
||||
row MySQL result set row from fetchrow()
|
||||
result Result set to use
|
||||
|
||||
DESCRIPTION
|
||||
This method simply iterates through a row returned via fetchrow with
|
||||
@ -761,15 +761,16 @@ ha_federated::ha_federated(TABLE_SHARE *table_arg)
|
||||
0 After fields have had field values stored from record
|
||||
*/
|
||||
|
||||
uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row)
|
||||
uint ha_federated::convert_row_to_internal_format(byte *record,
|
||||
MYSQL_ROW row,
|
||||
MYSQL_RES *result)
|
||||
{
|
||||
ulong *lengths;
|
||||
Field **field;
|
||||
my_bitmap_map *old_map= dbug_tmp_use_all_columns(table, table->write_set);
|
||||
DBUG_ENTER("ha_federated::convert_row_to_internal_format");
|
||||
|
||||
lengths= mysql_fetch_lengths(stored_result);
|
||||
memset(record, 0, table->s->null_bytes);
|
||||
lengths= mysql_fetch_lengths(result);
|
||||
|
||||
for (field= table->field; *field; field++, row++, lengths++)
|
||||
{
|
||||
@ -1314,12 +1315,11 @@ err:
|
||||
|
||||
static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
|
||||
{
|
||||
char *select_query, *tmp_table_name;
|
||||
char *select_query;
|
||||
char query_buffer[FEDERATED_QUERY_BUFFER_SIZE];
|
||||
uint tmp_table_name_length;
|
||||
Field **field;
|
||||
String query(query_buffer, sizeof(query_buffer), &my_charset_bin);
|
||||
FEDERATED_SHARE *share;
|
||||
FEDERATED_SHARE *share= NULL, tmp_share;
|
||||
/*
|
||||
In order to use this string, we must first zero it's length,
|
||||
or it will contain garbage
|
||||
@ -1327,12 +1327,15 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
|
||||
query.length(0);
|
||||
|
||||
pthread_mutex_lock(&federated_mutex);
|
||||
tmp_table_name= table->s->table_name.str;
|
||||
tmp_table_name_length= table->s->table_name.length;
|
||||
|
||||
if (parse_url(&tmp_share, table, 0))
|
||||
goto error;
|
||||
|
||||
/* TODO: change tmp_share.scheme to LEX_STRING object */
|
||||
if (!(share= (FEDERATED_SHARE *) hash_search(&federated_open_tables,
|
||||
(byte*) table_name,
|
||||
tmp_table_name_length)))
|
||||
(byte*) tmp_share.scheme,
|
||||
tmp_share.
|
||||
connect_string_length)))
|
||||
{
|
||||
query.set_charset(system_charset_info);
|
||||
query.append(FEDERATED_SELECT);
|
||||
@ -1350,18 +1353,15 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
|
||||
if (!(share= (FEDERATED_SHARE *)
|
||||
my_multi_malloc(MYF(MY_WME),
|
||||
&share, sizeof(*share),
|
||||
&tmp_table_name, tmp_table_name_length+ 1,
|
||||
&select_query,
|
||||
query.length()+table->s->connect_string.length+1,
|
||||
NullS)))
|
||||
{
|
||||
pthread_mutex_unlock(&federated_mutex);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (parse_url(share, table, 0))
|
||||
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(FEDERATED_BTICK);
|
||||
share->select_query= select_query;
|
||||
@ -1382,11 +1382,8 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
|
||||
|
||||
error:
|
||||
pthread_mutex_unlock(&federated_mutex);
|
||||
if (share->scheme)
|
||||
{
|
||||
my_free((gptr) share->scheme, MYF(0));
|
||||
share->scheme= 0;
|
||||
}
|
||||
my_free((gptr) tmp_share.scheme, MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free((gptr) share, MYF(MY_ALLOW_ZERO_PTR));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
@ -1406,13 +1403,7 @@ static int free_share(FEDERATED_SHARE *share)
|
||||
{
|
||||
hash_delete(&federated_open_tables, (byte*) share);
|
||||
my_free((gptr) share->scheme, MYF(MY_ALLOW_ZERO_PTR));
|
||||
share->scheme= 0;
|
||||
if (share->socket)
|
||||
{
|
||||
my_free((gptr) share->socket, MYF(MY_ALLOW_ZERO_PTR));
|
||||
share->socket= 0;
|
||||
}
|
||||
|
||||
my_free((gptr) share->socket, MYF(MY_ALLOW_ZERO_PTR));
|
||||
thr_lock_delete(&share->lock);
|
||||
VOID(pthread_mutex_destroy(&share->mutex));
|
||||
my_free((gptr) share, MYF(0));
|
||||
@ -1474,14 +1465,15 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
|
||||
|
||||
/* Connect to foreign database mysql_real_connect() */
|
||||
mysql= mysql_init(0);
|
||||
if (!mysql_real_connect(mysql,
|
||||
share->hostname,
|
||||
share->username,
|
||||
share->password,
|
||||
share->database,
|
||||
share->port,
|
||||
share->socket, 0))
|
||||
if (!mysql || !mysql_real_connect(mysql,
|
||||
share->hostname,
|
||||
share->username,
|
||||
share->password,
|
||||
share->database,
|
||||
share->port,
|
||||
share->socket, 0))
|
||||
{
|
||||
free_share(share);
|
||||
DBUG_RETURN(stash_remote_error());
|
||||
}
|
||||
/*
|
||||
@ -1491,6 +1483,11 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
|
||||
*/
|
||||
mysql->reconnect= 1;
|
||||
|
||||
ref_length= (table->s->primary_key != MAX_KEY ?
|
||||
table->key_info[table->s->primary_key].key_length :
|
||||
table->s->reclength);
|
||||
DBUG_PRINT("info", ("ref_length: %u", ref_length));
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -1514,13 +1511,12 @@ int ha_federated::close(void)
|
||||
/* free the result set */
|
||||
if (stored_result)
|
||||
{
|
||||
DBUG_PRINT("info",
|
||||
("mysql_free_result result at address %lx", stored_result));
|
||||
mysql_free_result(stored_result);
|
||||
stored_result= 0;
|
||||
}
|
||||
/* Disconnect from mysql */
|
||||
mysql_close(mysql);
|
||||
if (mysql) // QQ is this really needed
|
||||
mysql_close(mysql);
|
||||
retval= free_share(share);
|
||||
DBUG_RETURN(retval);
|
||||
|
||||
@ -1686,8 +1682,6 @@ int ha_federated::write_row(byte *buf)
|
||||
/* add the values */
|
||||
insert_string.append(values_string);
|
||||
|
||||
DBUG_PRINT("info", ("insert query %s", insert_string.c_ptr_quick()));
|
||||
|
||||
if (mysql_real_query(mysql, insert_string.ptr(), insert_string.length()))
|
||||
{
|
||||
DBUG_RETURN(stash_remote_error());
|
||||
@ -1763,7 +1757,7 @@ int ha_federated::repair(THD* thd, HA_CHECK_OPT* check_opt)
|
||||
query.append(FEDERATED_EXTENDED);
|
||||
if (check_opt->sql_flags & TT_USEFRM)
|
||||
query.append(FEDERATED_USE_FRM);
|
||||
|
||||
|
||||
if (mysql_real_query(mysql, query.ptr(), query.length()))
|
||||
{
|
||||
DBUG_RETURN(stash_remote_error());
|
||||
@ -1919,7 +1913,7 @@ int ha_federated::update_row(const byte *old_data, byte *new_data)
|
||||
/*
|
||||
This will delete a row. 'buf' will contain a copy of the row to be =deleted.
|
||||
The server will call this right after the current row has been called (from
|
||||
either a previous rnd_nexT() or index call).
|
||||
either a previous rnd_next() or index call).
|
||||
If you keep a pointer to the last row or can access a primary key it will
|
||||
make doing the deletion quite a bit easier.
|
||||
Keep in mind that the server does no guarentee consecutive deletions.
|
||||
@ -1985,6 +1979,7 @@ int ha_federated::delete_row(const byte *buf)
|
||||
DBUG_RETURN(stash_remote_error());
|
||||
}
|
||||
stats.deleted+= mysql->affected_rows;
|
||||
stats.records-= mysql->affected_rows;
|
||||
DBUG_PRINT("info",
|
||||
("rows deleted %d rows deleted for all time %d",
|
||||
int(mysql->affected_rows), stats.deleted));
|
||||
@ -2001,12 +1996,15 @@ int ha_federated::delete_row(const byte *buf)
|
||||
*/
|
||||
|
||||
int ha_federated::index_read(byte *buf, const byte *key,
|
||||
uint key_len, enum ha_rkey_function find_flag)
|
||||
uint key_len, ha_rkey_function find_flag)
|
||||
{
|
||||
int retval;
|
||||
DBUG_ENTER("ha_federated::index_read");
|
||||
retval= index_read_idx(buf, active_index, key, key_len, find_flag);
|
||||
DBUG_RETURN(retval);
|
||||
|
||||
if (stored_result)
|
||||
mysql_free_result(stored_result);
|
||||
DBUG_RETURN(index_read_idx_with_result_set(buf, active_index, key,
|
||||
key_len, find_flag,
|
||||
&stored_result));
|
||||
}
|
||||
|
||||
|
||||
@ -2015,26 +2013,60 @@ int ha_federated::index_read(byte *buf, const byte *key,
|
||||
row if any. This is only used to read whole keys.
|
||||
|
||||
This method is called via index_read in the case of a WHERE clause using
|
||||
a regular non-primary key index, OR is called DIRECTLY when the WHERE clause
|
||||
a primary key index OR is called DIRECTLY when the WHERE clause
|
||||
uses a PRIMARY KEY index.
|
||||
|
||||
NOTES
|
||||
This uses an internal result set that is deleted before function
|
||||
returns. We need to be able to be calable from ha_rnd_pos()
|
||||
*/
|
||||
|
||||
int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
|
||||
uint key_len, enum ha_rkey_function find_flag)
|
||||
{
|
||||
int retval;
|
||||
MYSQL_RES *mysql_result;
|
||||
DBUG_ENTER("ha_federated::index_read_idx");
|
||||
|
||||
if ((retval= index_read_idx_with_result_set(buf, index, key,
|
||||
key_len, find_flag,
|
||||
&mysql_result)))
|
||||
DBUG_RETURN(retval);
|
||||
mysql_free_result(mysql_result);
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Create result set for rows matching query and return first row
|
||||
|
||||
RESULT
|
||||
0 ok In this case *result will contain the result set
|
||||
table->status == 0
|
||||
# error In this case *result will contain 0
|
||||
table->status == STATUS_NOT_FOUND
|
||||
*/
|
||||
|
||||
int ha_federated::index_read_idx_with_result_set(byte *buf, uint index,
|
||||
const byte *key,
|
||||
uint key_len,
|
||||
ha_rkey_function find_flag,
|
||||
MYSQL_RES **result)
|
||||
{
|
||||
int retval;
|
||||
char error_buffer[FEDERATED_QUERY_BUFFER_SIZE];
|
||||
char index_value[STRING_BUFFER_USUAL_SIZE];
|
||||
char sql_query_buffer[FEDERATED_QUERY_BUFFER_SIZE];
|
||||
String index_string(index_value,
|
||||
String index_string(index_value,
|
||||
sizeof(index_value),
|
||||
&my_charset_bin);
|
||||
String sql_query(sql_query_buffer,
|
||||
sizeof(sql_query_buffer),
|
||||
&my_charset_bin);
|
||||
key_range range;
|
||||
DBUG_ENTER("ha_federated::index_read_idx");
|
||||
DBUG_ENTER("ha_federated::index_read_idx_with_result_set");
|
||||
|
||||
*result= 0; // In case of errors
|
||||
index_string.length(0);
|
||||
sql_query.length(0);
|
||||
statistic_increment(table->in_use->status_var.ha_read_key_count,
|
||||
@ -2051,20 +2083,6 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
|
||||
NULL, 0, 0);
|
||||
sql_query.append(index_string);
|
||||
|
||||
DBUG_PRINT("info",
|
||||
("current key %d key value %s index_string value %s length %d",
|
||||
index, (char*) key, index_string.c_ptr_quick(),
|
||||
index_string.length()));
|
||||
|
||||
DBUG_PRINT("info",
|
||||
("current position %d sql_query %s", current_position,
|
||||
sql_query.c_ptr_quick()));
|
||||
|
||||
if (stored_result)
|
||||
{
|
||||
mysql_free_result(stored_result);
|
||||
stored_result= 0;
|
||||
}
|
||||
if (mysql_real_query(mysql, sql_query.ptr(), sql_query.length()))
|
||||
{
|
||||
my_sprintf(error_buffer, (error_buffer, "error: %d '%s'",
|
||||
@ -2072,45 +2090,41 @@ int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
|
||||
retval= ER_QUERY_ON_FOREIGN_DATA_SOURCE;
|
||||
goto error;
|
||||
}
|
||||
stored_result= mysql_store_result(mysql);
|
||||
|
||||
if (!stored_result)
|
||||
if (!(*result= mysql_store_result(mysql)))
|
||||
{
|
||||
retval= HA_ERR_END_OF_FILE;
|
||||
goto error;
|
||||
}
|
||||
/*
|
||||
This basically says that the record in table->record[0] is legal,
|
||||
and that it is ok to use this record, for whatever reason, such
|
||||
as with a join (without it, joins will not work)
|
||||
*/
|
||||
table->status= 0;
|
||||
if (!(retval= read_next(buf, *result)))
|
||||
DBUG_RETURN(retval);
|
||||
|
||||
retval= rnd_next(buf);
|
||||
mysql_free_result(*result);
|
||||
*result= 0;
|
||||
table->status= STATUS_NOT_FOUND;
|
||||
DBUG_RETURN(retval);
|
||||
|
||||
error:
|
||||
if (stored_result)
|
||||
{
|
||||
mysql_free_result(stored_result);
|
||||
stored_result= 0;
|
||||
}
|
||||
table->status= STATUS_NOT_FOUND;
|
||||
my_error(retval, MYF(0), error_buffer);
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
|
||||
|
||||
/* Initialized at each key walk (called multiple times unlike rnd_init()) */
|
||||
|
||||
int ha_federated::index_init(uint keynr, bool sorted)
|
||||
{
|
||||
DBUG_ENTER("ha_federated::index_init");
|
||||
DBUG_PRINT("info",
|
||||
("table: '%s' key: %d", table->s->table_name.str, keynr));
|
||||
DBUG_PRINT("info", ("table: '%s' key: %u", table->s->table_name, keynr));
|
||||
active_index= keynr;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Read first range
|
||||
*/
|
||||
|
||||
int ha_federated::read_range_first(const key_range *start_key,
|
||||
const key_range *end_key,
|
||||
bool eq_range, bool sorted)
|
||||
@ -2122,8 +2136,7 @@ int ha_federated::read_range_first(const key_range *start_key,
|
||||
&my_charset_bin);
|
||||
DBUG_ENTER("ha_federated::read_range_first");
|
||||
|
||||
if (start_key == NULL && end_key == NULL)
|
||||
DBUG_RETURN(0);
|
||||
DBUG_ASSERT(!(start_key == NULL && end_key == NULL));
|
||||
|
||||
sql_query.length(0);
|
||||
sql_query.append(share->select_query);
|
||||
@ -2131,6 +2144,11 @@ int ha_federated::read_range_first(const key_range *start_key,
|
||||
&table->key_info[active_index],
|
||||
start_key, end_key, 0, eq_range);
|
||||
|
||||
if (stored_result)
|
||||
{
|
||||
mysql_free_result(stored_result);
|
||||
stored_result= 0;
|
||||
}
|
||||
if (mysql_real_query(mysql, sql_query.ptr(), sql_query.length()))
|
||||
{
|
||||
retval= ER_QUERY_ON_FOREIGN_DATA_SOURCE;
|
||||
@ -2138,38 +2156,21 @@ int ha_federated::read_range_first(const key_range *start_key,
|
||||
}
|
||||
sql_query.length(0);
|
||||
|
||||
if (stored_result)
|
||||
{
|
||||
DBUG_PRINT("info",
|
||||
("mysql_free_result address %lx", stored_result));
|
||||
mysql_free_result(stored_result);
|
||||
stored_result= 0;
|
||||
}
|
||||
stored_result= mysql_store_result(mysql);
|
||||
|
||||
if (!stored_result)
|
||||
if (!(stored_result= mysql_store_result(mysql)))
|
||||
{
|
||||
retval= HA_ERR_END_OF_FILE;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* This was successful, please let it be known! */
|
||||
table->status= 0;
|
||||
|
||||
retval= rnd_next(table->record[0]);
|
||||
retval= read_next(table->record[0], stored_result);
|
||||
DBUG_RETURN(retval);
|
||||
|
||||
error:
|
||||
table->status= STATUS_NOT_FOUND;
|
||||
if (stored_result)
|
||||
{
|
||||
DBUG_PRINT("info", ("mysql_free_result address %lx", stored_result));
|
||||
mysql_free_result(stored_result);
|
||||
stored_result= 0;
|
||||
}
|
||||
DBUG_RETURN(retval);
|
||||
table->status= STATUS_NOT_FOUND;
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
|
||||
|
||||
int ha_federated::read_range_next()
|
||||
{
|
||||
int retval;
|
||||
@ -2182,13 +2183,13 @@ int ha_federated::read_range_next()
|
||||
/* Used to read forward through the index. */
|
||||
int ha_federated::index_next(byte *buf)
|
||||
{
|
||||
int retval;
|
||||
DBUG_ENTER("ha_federated::index_next");
|
||||
statistic_increment(table->in_use->status_var.ha_read_next_count,
|
||||
&LOCK_status);
|
||||
retval= rnd_next(buf);
|
||||
DBUG_RETURN(retval);
|
||||
DBUG_RETURN(read_next(buf, stored_result));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
rnd_init() is called when the system wants the storage engine to do a table
|
||||
scan.
|
||||
@ -2242,11 +2243,8 @@ int ha_federated::rnd_init(bool scan)
|
||||
|
||||
if (scan)
|
||||
{
|
||||
DBUG_PRINT("info", ("share->select_query %s", share->select_query));
|
||||
if (stored_result)
|
||||
{
|
||||
DBUG_PRINT("info",
|
||||
("mysql_free_result address %lx", stored_result));
|
||||
mysql_free_result(stored_result);
|
||||
stored_result= 0;
|
||||
}
|
||||
@ -2263,28 +2261,25 @@ int ha_federated::rnd_init(bool scan)
|
||||
DBUG_RETURN(0);
|
||||
|
||||
error:
|
||||
DBUG_RETURN(stash_remote_error());
|
||||
DBUG_RETURN(stash_remote_error());
|
||||
}
|
||||
|
||||
|
||||
int ha_federated::rnd_end()
|
||||
{
|
||||
int retval;
|
||||
DBUG_ENTER("ha_federated::rnd_end");
|
||||
|
||||
if (stored_result)
|
||||
{
|
||||
DBUG_PRINT("info", ("mysql_free_result address %lx", stored_result));
|
||||
mysql_free_result(stored_result);
|
||||
stored_result= 0;
|
||||
}
|
||||
retval= index_end();
|
||||
DBUG_RETURN(retval);
|
||||
DBUG_RETURN(index_end());
|
||||
}
|
||||
|
||||
|
||||
int ha_federated::index_end(void)
|
||||
{
|
||||
DBUG_ENTER("ha_federated::index_end");
|
||||
if (stored_result)
|
||||
{
|
||||
mysql_free_result(stored_result);
|
||||
stored_result= 0;
|
||||
}
|
||||
active_index= MAX_KEY;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
@ -2302,8 +2297,6 @@ int ha_federated::index_end(void)
|
||||
|
||||
int ha_federated::rnd_next(byte *buf)
|
||||
{
|
||||
int retval;
|
||||
MYSQL_ROW row;
|
||||
DBUG_ENTER("ha_federated::rnd_next");
|
||||
|
||||
if (stored_result == 0)
|
||||
@ -2311,32 +2304,60 @@ int ha_federated::rnd_next(byte *buf)
|
||||
/*
|
||||
Return value of rnd_init is not always checked (see records.cc),
|
||||
so we can get here _even_ if there is _no_ pre-fetched result-set!
|
||||
TODO: fix it.
|
||||
*/
|
||||
TODO: fix it. We can delete this in 5.1 when rnd_init() is checked.
|
||||
*/
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
DBUG_RETURN(read_next(buf, stored_result));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
ha_federated::read_next
|
||||
|
||||
reads from a result set and converts to mysql internal
|
||||
format
|
||||
|
||||
SYNOPSIS
|
||||
field_in_record_is_null()
|
||||
buf byte pointer to record
|
||||
result mysql result set
|
||||
|
||||
DESCRIPTION
|
||||
This method is a wrapper method that reads one record from a result
|
||||
set and converts it to the internal table format
|
||||
|
||||
RETURN VALUE
|
||||
1 error
|
||||
0 no error
|
||||
*/
|
||||
|
||||
int ha_federated::read_next(byte *buf, MYSQL_RES *result)
|
||||
{
|
||||
int retval;
|
||||
my_ulonglong num_rows;
|
||||
MYSQL_ROW row;
|
||||
DBUG_ENTER("ha_federated::read_next");
|
||||
|
||||
table->status= STATUS_NOT_FOUND; // For easier return
|
||||
|
||||
/* Fetch a row, insert it back in a row format. */
|
||||
current_position= stored_result->data_cursor;
|
||||
DBUG_PRINT("info", ("current position %d", current_position));
|
||||
if (!(row= mysql_fetch_row(stored_result)))
|
||||
if (!(row= mysql_fetch_row(result)))
|
||||
DBUG_RETURN(HA_ERR_END_OF_FILE);
|
||||
|
||||
retval= convert_row_to_internal_format(buf, row);
|
||||
if (!(retval= convert_row_to_internal_format(buf, row, result)))
|
||||
table->status= 0;
|
||||
|
||||
DBUG_RETURN(retval);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
'position()' is called after each call to rnd_next() if the data needs to be
|
||||
ordered. You can do something like the following to store the position:
|
||||
my_store_ptr(ref, ref_length, current_position);
|
||||
store reference to current row so that we can later find it for
|
||||
a re-read, update or delete.
|
||||
|
||||
The server uses ref to store data. ref_length in the above case is the size
|
||||
needed to store current_position. ref is just a byte array that the server
|
||||
will maintain. If you are using offsets to mark rows, then current_position
|
||||
should be the offset. If it is a primary key like in BDB, then it needs to
|
||||
be a primary key.
|
||||
In case of federated, a reference is either a primary key or
|
||||
the whole record.
|
||||
|
||||
Called from filesort.cc, sql_select.cc, sql_delete.cc and sql_update.cc.
|
||||
*/
|
||||
@ -2344,32 +2365,44 @@ int ha_federated::rnd_next(byte *buf)
|
||||
void ha_federated::position(const byte *record)
|
||||
{
|
||||
DBUG_ENTER("ha_federated::position");
|
||||
/* my_store_ptr Add seek storage */
|
||||
*(MYSQL_ROW_OFFSET *) ref= current_position; // ref is always aligned
|
||||
if (table->s->primary_key != MAX_KEY)
|
||||
key_copy(ref, (byte *)record, table->key_info + table->s->primary_key,
|
||||
ref_length);
|
||||
else
|
||||
memcpy(ref, record, ref_length);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
This is like rnd_next, but you are given a position to use to determine the
|
||||
row. The position will be of the type that you stored in ref. You can use
|
||||
ha_get_ptr(pos,ref_length) to retrieve whatever key or position you saved
|
||||
when position() was called.
|
||||
row. The position will be of the type that you stored in ref.
|
||||
|
||||
This method is required for an ORDER BY.
|
||||
This method is required for an ORDER BY
|
||||
|
||||
Called from filesort.cc records.cc sql_insert.cc sql_select.cc sql_update.cc.
|
||||
*/
|
||||
|
||||
int ha_federated::rnd_pos(byte *buf, byte *pos)
|
||||
{
|
||||
int result;
|
||||
DBUG_ENTER("ha_federated::rnd_pos");
|
||||
|
||||
statistic_increment(table->in_use->status_var.ha_read_rnd_count,
|
||||
&LOCK_status);
|
||||
memcpy_fixed(¤t_position, pos, sizeof(MYSQL_ROW_OFFSET));
|
||||
stored_result->current_row= 0;
|
||||
stored_result->data_cursor= current_position;
|
||||
DBUG_RETURN(rnd_next(buf));
|
||||
if (table->s->primary_key != MAX_KEY)
|
||||
{
|
||||
/* We have a primary key, so use index_read_idx to find row */
|
||||
result= index_read_idx(buf, table->s->primary_key, pos,
|
||||
ref_length, HA_READ_KEY_EXACT);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* otherwise, get the old record ref as obtained in ::position */
|
||||
memcpy(buf, pos, ref_length);
|
||||
result= 0;
|
||||
}
|
||||
table->status= result ? STATUS_NOT_FOUND : 0;
|
||||
DBUG_RETURN(result);
|
||||
}
|
||||
|
||||
|
||||
@ -2462,7 +2495,7 @@ void ha_federated::info(uint flag)
|
||||
|
||||
if (flag & HA_STATUS_VARIABLE | HA_STATUS_CONST)
|
||||
{
|
||||
/*
|
||||
/*
|
||||
deleted is set in ha_federated::info
|
||||
*/
|
||||
/*
|
||||
@ -2474,11 +2507,13 @@ void ha_federated::info(uint flag)
|
||||
delete_length = ?
|
||||
*/
|
||||
if (row[4] != NULL)
|
||||
stats.records= (ha_rows) my_strtoll10(row[4], (char**) 0,
|
||||
stats.records= (ha_rows) my_strtoll10(row[4], (char**) 0,
|
||||
&error);
|
||||
if (row[5] != NULL)
|
||||
stats.mean_rec_length= (ha_rows) my_strtoll10(row[5], (char**) 0,
|
||||
&error);
|
||||
stats.mean_rec_length= (ha_rows) my_strtoll10(row[5], (char**) 0, &error);
|
||||
|
||||
stats.data_file_length= stats.records * stats.mean_rec_length;
|
||||
|
||||
if (row[12] != NULL)
|
||||
stats.update_time= (ha_rows) my_strtoll10(row[12], (char**) 0,
|
||||
&error);
|
||||
@ -2486,8 +2521,13 @@ void ha_federated::info(uint flag)
|
||||
stats.check_time= (ha_rows) my_strtoll10(row[13], (char**) 0,
|
||||
&error);
|
||||
}
|
||||
/*
|
||||
size of IO operations (This is based on a good guess, no high science
|
||||
involved)
|
||||
*/
|
||||
if (flag & HA_STATUS_CONST)
|
||||
stats.block_size= 4096;
|
||||
|
||||
}
|
||||
|
||||
if (result)
|
||||
@ -2498,6 +2538,7 @@ void ha_federated::info(uint flag)
|
||||
error:
|
||||
if (result)
|
||||
mysql_free_result(result);
|
||||
|
||||
my_sprintf(error_buffer, (error_buffer, ": %d : %s",
|
||||
mysql_errno(mysql), mysql_error(mysql)));
|
||||
my_error(error_code, MYF(0), error_buffer);
|
||||
@ -2578,6 +2619,7 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
|
||||
THR_LOCK_DATA **to,
|
||||
enum thr_lock_type lock_type)
|
||||
{
|
||||
DBUG_ENTER("ha_federated::store_lock");
|
||||
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
|
||||
{
|
||||
/*
|
||||
@ -2607,7 +2649,7 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
|
||||
|
||||
*to++= &lock;
|
||||
|
||||
return to;
|
||||
DBUG_RETURN(to);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -130,6 +130,7 @@ typedef struct st_federated_share {
|
||||
remote host info, parse_url supplies
|
||||
*/
|
||||
char *scheme;
|
||||
char *connect_string;
|
||||
char *hostname;
|
||||
char *username;
|
||||
char *password;
|
||||
@ -139,7 +140,7 @@ typedef struct st_federated_share {
|
||||
char *socket;
|
||||
char *sport;
|
||||
ushort port;
|
||||
uint table_name_length, use_count;
|
||||
uint table_name_length, connect_string_length, use_count;
|
||||
pthread_mutex_t mutex;
|
||||
THR_LOCK lock;
|
||||
} FEDERATED_SHARE;
|
||||
@ -153,7 +154,6 @@ class ha_federated: public handler
|
||||
FEDERATED_SHARE *share; /* Shared lock info */
|
||||
MYSQL *mysql; /* MySQL connection */
|
||||
MYSQL_RES *stored_result;
|
||||
uint ref_length;
|
||||
uint fetch_num; // stores the fetch num
|
||||
MYSQL_ROW_OFFSET current_position; // Current position used by ::position()
|
||||
int remote_error_number;
|
||||
@ -164,7 +164,8 @@ private:
|
||||
return 0 on success
|
||||
return errorcode otherwise
|
||||
*/
|
||||
uint convert_row_to_internal_format(byte *buf, MYSQL_ROW row);
|
||||
uint convert_row_to_internal_format(byte *buf, MYSQL_ROW row,
|
||||
MYSQL_RES *row);
|
||||
bool create_where_from_key(String *to, KEY *key_info,
|
||||
const key_range *start_key,
|
||||
const key_range *end_key,
|
||||
@ -304,6 +305,13 @@ public:
|
||||
int connection_rollback();
|
||||
int connection_autocommit(bool state);
|
||||
int execute_simple_query(const char *query, int len);
|
||||
|
||||
int read_next(byte *buf, MYSQL_RES *result);
|
||||
int index_read_idx_with_result_set(byte *buf, uint index,
|
||||
const byte *key,
|
||||
uint key_len,
|
||||
ha_rkey_function find_flag,
|
||||
MYSQL_RES **result);
|
||||
};
|
||||
|
||||
int federated_db_init(void);
|
||||
|
Loading…
x
Reference in New Issue
Block a user