Commit 65492347 authored by unknown's avatar unknown

Merge pgalbraith@bk-internal.mysql.com:/home/bk/mysql-5.0

into krsna.patg.net:/home/patg/mysql-5.0


sql/handler.cc:
  Auto merged
parents bf46e486 39e14ac1
...@@ -499,6 +499,8 @@ MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *result, ...@@ -499,6 +499,8 @@ MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *result,
MYSQL_FIELD_OFFSET offset); MYSQL_FIELD_OFFSET offset);
MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result); MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result);
unsigned long * STDCALL mysql_fetch_lengths(MYSQL_RES *result); unsigned long * STDCALL mysql_fetch_lengths(MYSQL_RES *result);
void STDCALL cli_fetch_lengths(unsigned long *to, MYSQL_ROW column,
unsigned int field_count);
MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *result); MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *result);
MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table, MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table,
const char *wild); const char *wild);
......
...@@ -644,14 +644,19 @@ select * from federated.t1 where fileguts = 'jimbob'; ...@@ -644,14 +644,19 @@ select * from federated.t1 where fileguts = 'jimbob';
id code fileguts creation_date entered_time id code fileguts creation_date entered_time
3 DEUEUEUEUEUEUEUEUEU jimbob 2004-04-04 04:04:04 2004-04-04 04:04:04 3 DEUEUEUEUEUEUEUEUEU jimbob 2004-04-04 04:04:04 2004-04-04 04:04:04
drop table if exists federated.t1; drop table if exists federated.t1;
CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id)); CREATE TABLE federated.t1 (a BLOB);
drop table if exists federated.t1; drop table if exists federated.t1;
CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1'; CREATE TABLE federated.t1 (a BLOB) ENGINE="FEDERATED" COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
insert into federated.t1 (name, country_id, other) values ('Kumar', 1, 11111); INSERT INTO federated.t1 VALUES (0x00);
insert into federated.t1 (name, country_id, other) values ('Lenz', 2, 22222); INSERT INTO federated.t1 VALUES (0x0001);
insert into federated.t1 (name, country_id, other) values ('Marizio', 3, 33333); INSERT INTO federated.t1 VALUES (0x0100);
insert into federated.t1 (name, country_id, other) values ('Monty', 4, 33333); SELECT HEX(a) FROM federated.t1;
insert into federated.t1 (name, country_id, other) values ('Sanja', 5, 33333); HEX(a)
00
0001
0100
drop table if exists federated.t1;
CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id));
drop table if exists federated.countries; drop table if exists federated.countries;
Warnings: Warnings:
Note 1051 Unknown table 'countries' Note 1051 Unknown table 'countries'
...@@ -661,6 +666,13 @@ insert into federated.countries (country) values ('Germany'); ...@@ -661,6 +666,13 @@ insert into federated.countries (country) values ('Germany');
insert into federated.countries (country) values ('Italy'); insert into federated.countries (country) values ('Italy');
insert into federated.countries (country) values ('Finland'); insert into federated.countries (country) values ('Finland');
insert into federated.countries (country) values ('Ukraine'); insert into federated.countries (country) values ('Ukraine');
drop table if exists federated.t1;
CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
insert into federated.t1 (name, country_id, other) values ('Kumar', 1, 11111);
insert into federated.t1 (name, country_id, other) values ('Lenz', 2, 22222);
insert into federated.t1 (name, country_id, other) values ('Marizio', 3, 33333);
insert into federated.t1 (name, country_id, other) values ('Monty', 4, 33333);
insert into federated.t1 (name, country_id, other) values ('Sanja', 5, 33333);
select federated.t1.*, federated.countries.country from federated.t1 left join federated.countries on federated.t1.country_id = federated.countries.id; select federated.t1.*, federated.countries.country from federated.t1 left join federated.countries on federated.t1.country_id = federated.countries.id;
id country_id name other country id country_id name other country
1 1 Kumar 11111 India 1 1 Kumar 11111 India
......
...@@ -522,8 +522,22 @@ insert into federated.t1 (code, fileguts, creation_date) values ('ASDFWERQWETWET ...@@ -522,8 +522,22 @@ insert into federated.t1 (code, fileguts, creation_date) values ('ASDFWERQWETWET
insert into federated.t1 (code, fileguts, creation_date) values ('DEUEUEUEUEUEUEUEUEU', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2004-04-04 04:04:04'); insert into federated.t1 (code, fileguts, creation_date) values ('DEUEUEUEUEUEUEUEUEU', '*()w*09*$()*#)(*09*^90*d)(*s()d8g)(s*ned)(*)(s*d)(*hn(d*)(*sbn)D((#$*(#*%%&#&^$#&#&#&#&^&#*&*#$*&^*(&#(&Q*&&(*!&!(*&*(#&*(%&#<S-F8>*<S-F8><S-F8><S-F8>#<S-F8>#<S-F8>#<S-F8>[[', '2004-04-04 04:04:04');
insert into federated.t1 (code, fileguts, creation_date) values ('DEUEUEUEUEUEUEUEUEU', 'jimbob', '2004-04-04 04:04:04'); insert into federated.t1 (code, fileguts, creation_date) values ('DEUEUEUEUEUEUEUEUEU', 'jimbob', '2004-04-04 04:04:04');
select * from federated.t1; select * from federated.t1;
select * from federated.t1 where fileguts = 'jimbob';
# test blob indexes # test blob indexes
select * from federated.t1 where fileguts = 'jimbob';
# test blob with binary
connection slave;
drop table if exists federated.t1;
CREATE TABLE federated.t1 (a BLOB);
connection master;
drop table if exists federated.t1;
CREATE TABLE federated.t1 (a BLOB) ENGINE="FEDERATED" COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
INSERT INTO federated.t1 VALUES (0x00);
INSERT INTO federated.t1 VALUES (0x0001);
INSERT INTO federated.t1 VALUES (0x0100);
SELECT HEX(a) FROM federated.t1;
# TODO # TODO
# #
...@@ -559,15 +573,6 @@ drop table if exists federated.t1; ...@@ -559,15 +573,6 @@ drop table if exists federated.t1;
CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id)); CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id));
connection master; connection master;
drop table if exists federated.t1;
CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
insert into federated.t1 (name, country_id, other) values ('Kumar', 1, 11111);
insert into federated.t1 (name, country_id, other) values ('Lenz', 2, 22222);
insert into federated.t1 (name, country_id, other) values ('Marizio', 3, 33333);
insert into federated.t1 (name, country_id, other) values ('Monty', 4, 33333);
insert into federated.t1 (name, country_id, other) values ('Sanja', 5, 33333);
drop table if exists federated.countries; drop table if exists federated.countries;
CREATE TABLE federated.countries ( `id` int(20) NOT NULL auto_increment, `country` varchar(32), primary key (id)); CREATE TABLE federated.countries ( `id` int(20) NOT NULL auto_increment, `country` varchar(32), primary key (id));
insert into federated.countries (country) values ('India'); insert into federated.countries (country) values ('India');
...@@ -576,6 +581,14 @@ insert into federated.countries (country) values ('Italy'); ...@@ -576,6 +581,14 @@ insert into federated.countries (country) values ('Italy');
insert into federated.countries (country) values ('Finland'); insert into federated.countries (country) values ('Finland');
insert into federated.countries (country) values ('Ukraine'); insert into federated.countries (country) values ('Ukraine');
drop table if exists federated.t1;
CREATE TABLE federated.t1 ( `id` int(20) NOT NULL auto_increment, `country_id` int(20) NOT NULL DEFAULT 0, `name` varchar(32), `other` varchar(20), PRIMARY KEY (`id`), key (country_id) ) ENGINE="FEDERATED" DEFAULT CHARSET=latin1 COMMENT='mysql://root@127.0.0.1:9308/federated/t1';
insert into federated.t1 (name, country_id, other) values ('Kumar', 1, 11111);
insert into federated.t1 (name, country_id, other) values ('Lenz', 2, 22222);
insert into federated.t1 (name, country_id, other) values ('Marizio', 3, 33333);
insert into federated.t1 (name, country_id, other) values ('Monty', 4, 33333);
insert into federated.t1 (name, country_id, other) values ('Sanja', 5, 33333);
select federated.t1.*, federated.countries.country from federated.t1 left join federated.countries on federated.t1.country_id = federated.countries.id; select federated.t1.*, federated.countries.country from federated.t1 left join federated.countries on federated.t1.country_id = federated.countries.id;
drop table federated.countries; drop table federated.countries;
......
...@@ -1121,7 +1121,7 @@ void mysql_read_default_options(struct st_mysql_options *options, ...@@ -1121,7 +1121,7 @@ void mysql_read_default_options(struct st_mysql_options *options,
else the lengths are calculated from the offset between pointers. else the lengths are calculated from the offset between pointers.
**************************************************************************/ **************************************************************************/
static void cli_fetch_lengths(ulong *to, MYSQL_ROW column, void cli_fetch_lengths(ulong *to, MYSQL_ROW column,
unsigned int field_count) unsigned int field_count)
{ {
ulong *prev_length; ulong *prev_length;
......
...@@ -343,10 +343,10 @@ ...@@ -343,10 +343,10 @@
./sql/ha_federated.cc ./sql/ha_federated.cc
./sql/ha_federated.h ./sql/ha_federated.h
*/ */
#ifdef __GNUC__ #ifdef __GNUC__
#pragma implementation // gcc: Class implementation #pragma implementation // gcc: Class implementation
#endif #endif
#include <mysql_priv.h> #include <mysql_priv.h>
...@@ -355,27 +355,74 @@ ...@@ -355,27 +355,74 @@
#include "ha_federated.h" #include "ha_federated.h"
#define MAX_REMOTE_SIZE IO_SIZE #define MAX_REMOTE_SIZE IO_SIZE
/* Variables for federated share methods */ /* Variables for federated share methods */
static HASH federated_open_tables; // Hash used to track open tables static HASH federated_open_tables; // Hash used to track open
pthread_mutex_t federated_mutex; // This is the mutex we use to init the hash // tables
static int federated_init= 0; // Variable for checking the init state of hash pthread_mutex_t federated_mutex; // This is the mutex we use to
// init the hash
static int federated_init= 0; // Variable for checking the
// init state of hash
/* /*
Function we use in the creation of our hash to get key. Function we use in the creation of our hash to get key.
*/ */
static byte* federated_get_key(FEDERATED_SHARE *share,uint *length, static byte *federated_get_key(FEDERATED_SHARE *share, uint *length,
my_bool not_used __attribute__((unused))) my_bool not_used __attribute__ ((unused)))
{ {
*length= share->table_name_length; *length= share->table_name_length;
return (byte*) share->table_name; return (byte*) share->table_name;
} }
/*
Initialize the federated handler.
SYNOPSIS
federated_db_init()
void
RETURN
FALSE OK
TRUE Error
*/
bool federated_db_init()
{
federated_init= 1;
VOID(pthread_mutex_init(&federated_mutex, MY_MUTEX_INIT_FAST));
return (hash_init(&federated_open_tables, system_charset_info, 32, 0, 0,
(hash_get_key) federated_get_key, 0, 0));
}
/*
Release the federated handler.
SYNOPSIS
federated_db_end()
void
RETURN
FALSE OK
*/
bool federated_db_end()
{
if (federated_init)
{
hash_free(&federated_open_tables);
VOID(pthread_mutex_destroy(&federated_mutex));
}
federated_init= 0;
return FALSE;
}
/* /*
Parse connection info from table->s->comment Parse connection info from table->s->comment
SYNOPSIS SYNOPSIS
parse_url() parse_url()
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
DESCRIPTION DESCRIPTION
populates the share with information about the connection populates the share with information about the connection
...@@ -385,10 +432,10 @@ static byte* federated_get_key(FEDERATED_SHARE *share,uint *length, ...@@ -385,10 +432,10 @@ static byte* federated_get_key(FEDERATED_SHARE *share,uint *length,
This string MUST be in the format of any of these: This string MUST be in the format of any of these:
scheme://username:password@hostname:port/database/table scheme://username:password@hostname:port/database/table
scheme://username@hostname/database/table scheme://username@hostname/database/table
scheme://username@hostname:port/database/table scheme://username@hostname:port/database/table
scheme://username:password@hostname/database/table scheme://username:password@hostname/database/table
An Example: An Example:
...@@ -401,31 +448,28 @@ scheme://username:password@hostname/database/table ...@@ -401,31 +448,28 @@ scheme://username:password@hostname/database/table
RETURN VALUE RETURN VALUE
0 success 0 success
-1 failure, wrong string format 1 failure, wrong string format
*/ */
static int parse_url(FEDERATED_SHARE *share, TABLE *table, uint table_create_flag) static int parse_url(FEDERATED_SHARE *share, TABLE *table,
uint table_create_flag)
{ {
DBUG_ENTER("ha_federated::parse_url"); DBUG_ENTER("ha_federated::parse_url");
// This either get set or will remain the same.
share->port= 0; share->port= 0;
uint error_num= table_create_flag ? ER_CANT_CREATE_TABLE : ER_CONNECT_TO_MASTER ; uint error_num= table_create_flag ? ER_CANT_CREATE_TABLE :
ER_CONNECT_TO_MASTER;
share->scheme= my_strdup(table->s->comment, MYF(0)); share->scheme= my_strdup(table->s->comment, MYF(0));
if ((share->username= strstr(share->scheme, "://"))) if ((share->username= strstr(share->scheme, "://")))
{ {
share->scheme[share->username - share->scheme] = '\0'; share->scheme[share->username - share->scheme]= '\0';
if (strcmp(share->scheme, "mysql") != 0) if (strcmp(share->scheme, "mysql") != 0)
{ {
DBUG_PRINT("ha_federated::parse_url",
("The federated handler currently only supports connecting\
to a MySQL database!!!\n"));
my_error(error_num, MYF(0), my_error(error_num, MYF(0),
"ERROR: federated handler only supports remote 'mysql://' database"); "ERROR: federated handler only supports remote 'mysql://' database");
DBUG_RETURN(-1); DBUG_RETURN(1);
} }
share->username+= 3; share->username+= 3;
...@@ -439,34 +483,34 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, uint table_create_fla ...@@ -439,34 +483,34 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, uint table_create_fla
share->username[share->password - share->username]= '\0'; share->username[share->password - share->username]= '\0';
share->password++; share->password++;
share->username= share->username; share->username= share->username;
// make sure there isn't an extra / or @ /*
make sure there isn't an extra / or @
*/
if ((strchr(share->password, '/') || strchr(share->hostname, '@'))) if ((strchr(share->password, '/') || strchr(share->hostname, '@')))
{ {
DBUG_PRINT("ha_federated::parse_url",
("this connection string is not in the correct format!!!\n"));
my_error(error_num, MYF(0), my_error(error_num, MYF(0),
"this connection string is not in the correct format!!!\n"); "this connection string is not in the correct format!!!\n");
DBUG_RETURN(-1); DBUG_RETURN(1);
} }
/* /*
Found that if the string is: Found that if the string is:
user:@hostname:port/database/table user:@hostname:port/database/table
Then password is a null string, so set to NULL Then password is a null string, so set to NULL
*/ */
if ((share->password[0] == '\0')) if ((share->password[0] == '\0'))
share->password= NULL; share->password= NULL;
} }
else else
share->username= share->username; share->username= share->username;
// make sure there isn't an extra / or @ /*
make sure there isn't an extra / or @
*/
if ((strchr(share->username, '/')) || (strchr(share->hostname, '@'))) if ((strchr(share->username, '/')) || (strchr(share->hostname, '@')))
{ {
DBUG_PRINT("ha_federated::parse_url",
("this connection string is not in the correct format!!!\n"));
my_error(error_num, MYF(0), my_error(error_num, MYF(0),
"this connection string is not in the correct format!!!\n"); "this connection string is not in the correct format!!!\n");
DBUG_RETURN(-1); DBUG_RETURN(1);
} }
if ((share->database= strchr(share->hostname, '/'))) if ((share->database= strchr(share->hostname, '/')))
...@@ -491,55 +535,56 @@ Then password is a null string, so set to NULL ...@@ -491,55 +535,56 @@ Then password is a null string, so set to NULL
} }
else else
{ {
DBUG_PRINT("ha_federated::parse_url",
("this connection string is not in the correct format!!!\n"));
my_error(error_num, MYF(0), my_error(error_num, MYF(0),
"this connection string is not in the correct format!!!\n"); "this connection string is not in the correct format!!!\n");
DBUG_RETURN(-1); DBUG_RETURN(1);
} }
} }
else else
{ {
DBUG_PRINT("ha_federated::parse_url",
("this connection string is not in the correct format!!!\n"));
my_error(error_num, MYF(0), my_error(error_num, MYF(0),
"this connection string is not in the correct format!!!\n"); "this connection string is not in the correct format!!!\n");
DBUG_RETURN(-1); DBUG_RETURN(1);
} }
// make sure there's not an extra / /*
make sure there's not an extra /
*/
if ((strchr(share->table_base_name, '/'))) if ((strchr(share->table_base_name, '/')))
{ {
DBUG_PRINT("ha_federated::parse_url",
("this connection string is not in the correct format!!!\n"));
my_error(error_num, MYF(0), my_error(error_num, MYF(0),
"this connection string is not in the correct format!!!\n"); "this connection string is not in the correct format!!!\n");
DBUG_RETURN(-1); DBUG_RETURN(1);
} }
if (share->hostname[0] == '\0') if (share->hostname[0] == '\0')
share->hostname= NULL; share->hostname= NULL;
DBUG_PRINT("ha_federated::parse_url", if (!share->port)
("scheme %s username %s password %s \ {
hostname %s port %d database %s tablename %s\n", if (strcmp(share->hostname, "localhost") == 0)
share->scheme, share->username, share->password, share->hostname, share->socket= my_strdup("/tmp/mysql.sock", MYF(0));
share->port, share->database, share->table_base_name)); else
share->port= 3306;
}
DBUG_PRINT("ha_federated::parse_url",
("scheme %s username %s password %s \
hostname %s port %d database %s tablename %s\n",
share->scheme, share->username, share->password,
share->hostname, share->port, share->database,
share->table_base_name));
} }
else else
{ {
DBUG_PRINT("ha_federated::parse_url",
("this connection string is not in the correct format!!!\n"));
my_error(error_num, MYF(0), my_error(error_num, MYF(0),
"this connection string is not in the correct format!!!\n"); "this connection string is not in the correct format!!!\n");
DBUG_RETURN(-1); DBUG_RETURN(1);
} }
} }
else else
{ {
DBUG_PRINT("ha_federated::parse_url",
("this connection string is not in the correct format!!!\n"));
my_error(error_num, MYF(0), my_error(error_num, MYF(0),
"this connection string is not in the correct format!!!\n"); "this connection string is not in the correct format!!!\n");
DBUG_RETURN(-1); DBUG_RETURN(1);
} }
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -564,24 +609,27 @@ Then password is a null string, so set to NULL ...@@ -564,24 +609,27 @@ Then password is a null string, so set to NULL
*/ */
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)
{ {
unsigned long len; ulong *lengths;
int x= 0; uint num_fields;
uint x= 0;
DBUG_ENTER("ha_federated::convert_row_to_internal_format"); DBUG_ENTER("ha_federated::convert_row_to_internal_format");
// Question this num_fields= mysql_num_fields(result);
memset(record, 0, table->s->null_bytes); lengths= (ulong*) my_malloc(num_fields * sizeof(ulong), MYF(0));
cli_fetch_lengths((ulong*) lengths, row, num_fields);
memset(record, 0, table->s->null_bytes);
for (Field **field=table->field; *field ; field++, x++) for (Field **field= table->field; *field; field++, x++)
{ {
if (!row[x]) if (!row[x])
(*field)->set_null(); (*field)->set_null();
else else
/* (*field)->store(row[x], lengths[x], &my_charset_bin);
changed system_charset_info to default_charset_info because
testing revealed that german text was not being retrieved properly
*/
(*field)->store(row[x], strlen(row[x]), &my_charset_bin);
} }
my_free((gptr) lengths, MYF(0));
lengths= 0;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
...@@ -595,29 +643,31 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info, ...@@ -595,29 +643,31 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info,
String tmp; String tmp;
DBUG_ENTER("ha_federated::create_where_from_key"); DBUG_ENTER("ha_federated::create_where_from_key");
for (key_part= key_info->key_part ; (int) key_length > 0 ; key_part++) for (key_part= key_info->key_part; (int) key_length > 0; key_part++)
{ {
Field *field= key_part->field; Field *field= key_part->field;
needs_quotes= field->needs_quotes(); needs_quotes= field->needs_quotes();
//bool needs_quotes= type_quote(field->type()); //bool needs_quotes= type_quote(field->type());
DBUG_PRINT("ha_federated::create_where_from_key", ("key name %s type %d", field->field_name, field->type())); DBUG_PRINT("ha_federated::create_where_from_key",
("key name %s type %d", field->field_name, field->type()));
uint length= key_part->length; uint length= key_part->length;
if (second_loop++ && to->append(" AND ",5)) if (second_loop++ && to->append(" AND ", 5))
DBUG_RETURN(1); DBUG_RETURN(1);
if (to->append('`') || to->append(field->field_name) || if (to->append('`') || to->append(field->field_name) || to->append("` ", 2))
to->append("` ",2)) DBUG_RETURN(1); // Out of memory
DBUG_RETURN(1); // Out of memory
if (key_part->null_bit) if (key_part->null_bit)
{ {
if (*key++) if (*key++)
{ {
if (to->append("IS NULL",7)) if (to->append("IS NULL", 7))
DBUG_PRINT("ha_federated::create_where_from_key", ("NULL type %s", to->c_ptr_quick()));
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_PRINT("ha_federated::create_where_from_key",
("NULL type %s", to->c_ptr_quick()));
key_length-= key_part->store_length; key_length-= key_part->store_length;
key+= key_part->store_length-1; key+= key_part->store_length - 1;
continue; continue;
} }
key_length--; key_length--;
...@@ -630,21 +680,22 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info, ...@@ -630,21 +680,22 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info,
{ {
/* This is can be threated as a hex string */ /* This is can be threated as a hex string */
Field_bit *field= (Field_bit *) (key_part->field); Field_bit *field= (Field_bit *) (key_part->field);
char buff[64+2], *ptr; char buff[64 + 2], *ptr;
byte *end= (byte *)(key) + length; byte *end= (byte*)(key)+length;
buff[0]='0'; buff[0]= '0';
buff[1]='x'; buff[1]= 'x';
for (ptr= buff+2 ; key < end ; key++) for (ptr= buff + 2; key < end; key++)
{ {
uint tmp= (uint) (uchar) *key; uint tmp= (uint)(uchar) *key;
*ptr++=_dig_vec_upper[tmp >> 4]; *ptr++= _dig_vec_upper[tmp >> 4];
*ptr++=_dig_vec_upper[tmp & 15]; *ptr++= _dig_vec_upper[tmp & 15];
} }
if (to->append(buff, (uint) (ptr-buff))) if (to->append(buff, (uint)(ptr - buff)))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_PRINT("ha_federated::create_where_from_key", ("bit type %s", to->c_ptr_quick())); DBUG_PRINT("ha_federated::create_where_from_key",
("bit type %s", to->c_ptr_quick()));
key_length-= length; key_length-= length;
continue; continue;
} }
...@@ -658,7 +709,8 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info, ...@@ -658,7 +709,8 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info,
if (append_escaped(to, &tmp)) if (append_escaped(to, &tmp))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_PRINT("ha_federated::create_where_from_key", ("blob type %s", to->c_ptr_quick())); DBUG_PRINT("ha_federated::create_where_from_key",
("blob type %s", to->c_ptr_quick()));
length= key_part->length; length= key_part->length;
} }
else if (key_part->key_part_flag & HA_VAR_LENGTH_PART) else if (key_part->key_part_flag & HA_VAR_LENGTH_PART)
...@@ -669,29 +721,33 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info, ...@@ -669,29 +721,33 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info,
if (append_escaped(to, &tmp)) if (append_escaped(to, &tmp))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_PRINT("ha_federated::create_where_from_key", ("varchar type %s", to->c_ptr_quick())); DBUG_PRINT("ha_federated::create_where_from_key",
("varchar type %s", to->c_ptr_quick()));
} }
else else
{ {
DBUG_PRINT("ha_federated::create_where_from_key", ("else block, unknown type so far")); DBUG_PRINT("ha_federated::create_where_from_key",
("else block, unknown type so far"));
char buff[MAX_FIELD_WIDTH]; char buff[MAX_FIELD_WIDTH];
String str(buff, sizeof(buff), field->charset()), *res; String str(buff, sizeof(buff), field->charset()), *res;
res= field->val_str(&str, (char *)(key)); res= field->val_str(&str, (char*) (key));
if (field->result_type() == STRING_RESULT) if (field->result_type() == STRING_RESULT)
{ {
if (append_escaped(to, res)) if (append_escaped(to, res))
DBUG_RETURN(1); DBUG_RETURN(1);
res= field->val_str(&str, (char *)(key)); res= field->val_str(&str, (char*) (key));
DBUG_PRINT("ha_federated::create_where_from_key", ("else block, string type", to->c_ptr_quick())); DBUG_PRINT("ha_federated::create_where_from_key",
("else block, string type", to->c_ptr_quick()));
} }
else if (to->append(res->ptr(), res->length())) else if (to->append(res->ptr(), res->length()))
DBUG_RETURN(1); DBUG_RETURN(1);
} }
if (needs_quotes && to->append("'")) if (needs_quotes && to->append("'"))
DBUG_RETURN(1); DBUG_RETURN(1);
DBUG_PRINT("ha_federated::create_where_from_key", ("final value for 'to' %s", to->c_ptr_quick())); DBUG_PRINT("ha_federated::create_where_from_key",
("final value for 'to' %s", to->c_ptr_quick()));
key+= length; key+= length;
key_length-= length; key_length-= length;
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -699,32 +755,6 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info, ...@@ -699,32 +755,6 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info,
DBUG_RETURN(1); DBUG_RETURN(1);
} }
int load_conn_info(FEDERATED_SHARE *share, TABLE *table)
{
DBUG_ENTER("ha_federated::load_conn_info");
int retcode;
retcode= parse_url(share, table, 0);
if (retcode < 0)
{
DBUG_PRINT("ha_federated::load_conn_info",
("retcode %d, setting defaults", retcode));
/* sanity checks to make sure all needed pieces are present */
if (!share->port)
{
if (strcmp(share->hostname, "localhost") == 0)
share->socket= my_strdup("/tmp/mysql.sock",MYF(0));
else
share->port= 3306;
}
}
DBUG_PRINT("ha_federated::load_conn_info",
("returned from retcode %d", retcode));
DBUG_RETURN(retcode);
}
/* /*
Example of simple lock controls. The "share" it creates is structure we will Example of simple lock controls. The "share" it creates is structure we will
pass to each federated handler. Do you have to have one of these? Well, you pass to each federated handler. Do you have to have one of these? Well, you
...@@ -740,79 +770,70 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) ...@@ -740,79 +770,70 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
uint table_name_length, table_base_name_length; uint table_name_length, table_base_name_length;
char *tmp_table_name, *tmp_table_base_name, *table_base_name, *select_query; char *tmp_table_name, *tmp_table_base_name, *table_base_name, *select_query;
// share->table_name has the file location - we want the actual table's /*
// name! share->table_name has the file location - we want the actual table's
table_base_name= (char *)table->s->table_name; name!
DBUG_PRINT("ha_federated::get_share",("table_name %s", table_base_name)); */
table_base_name= (char*) table->s->table_name;
DBUG_PRINT("ha_federated::get_share", ("table_name %s", table_base_name));
/* /*
So why does this exist? There is no way currently to init a storage engine. So why does this exist? There is no way currently to init a storage engine.
Innodb and BDB both have modifications to the server to allow them to Innodb and BDB both have modifications to the server to allow them to
do this. Since you will not want to do this, this is probably the next do this. Since you will not want to do this, this is probably the next
best method. best method.
*/ */
if (!federated_init)
{
/* Hijack a mutex for init'ing the storage engine */
pthread_mutex_lock(&LOCK_mysql_create_db);
if (!federated_init)
{
federated_init++;
VOID(pthread_mutex_init(&federated_mutex,MY_MUTEX_INIT_FAST));
(void) hash_init(&federated_open_tables,system_charset_info,32,0,0,
(hash_get_key) federated_get_key,0,0);
}
pthread_mutex_unlock(&LOCK_mysql_create_db);
}
pthread_mutex_lock(&federated_mutex); pthread_mutex_lock(&federated_mutex);
table_name_length= (uint) strlen(table_name); table_name_length= (uint) strlen(table_name);
table_base_name_length= (uint) strlen(table_base_name); table_base_name_length= (uint) strlen(table_base_name);
if (!(share= (FEDERATED_SHARE*) hash_search(&federated_open_tables, if (!(share= (FEDERATED_SHARE *) hash_search(&federated_open_tables,
(byte*) table_name, (byte*) table_name,
table_name_length))) table_name_length)))
{ {
query.set_charset(system_charset_info); query.set_charset(system_charset_info);
query.append("SELECT * FROM "); query.append("SELECT * FROM ");
query.append(table_base_name); query.append(table_base_name);
if (!(share= (FEDERATED_SHARE *) if (!(share= (FEDERATED_SHARE *)
my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), my_multi_malloc(MYF(MY_WME | MY_ZEROFILL),
&share, sizeof(*share), &share, sizeof(*share),
&tmp_table_name, table_name_length+1, &tmp_table_name, table_name_length + 1,
&tmp_table_base_name, table_base_name_length+1, &tmp_table_base_name, table_base_name_length + 1,
&select_query, query.length()+1, &select_query, query.length() + 1, NullS)))
NullS)))
{ {
pthread_mutex_unlock(&federated_mutex); pthread_mutex_unlock(&federated_mutex);
return NULL; return NULL;
} }
load_conn_info(share, table); if (parse_url(share, table, 0))
goto error;
share->use_count= 0; share->use_count= 0;
share->table_name_length= table_name_length; share->table_name_length= table_name_length;
share->table_name= tmp_table_name; share->table_name= tmp_table_name;
share->table_base_name_length= table_base_name_length; share->table_base_name_length= table_base_name_length;
share->table_base_name= tmp_table_base_name; share->table_base_name= tmp_table_base_name;
share->select_query= select_query; share->select_query= select_query;
strmov(share->table_name,table_name); strmov(share->table_name, table_name);
strmov(share->table_base_name,table_base_name); strmov(share->table_base_name, table_base_name);
strmov(share->select_query,query.c_ptr_quick()); strmov(share->select_query, query.ptr());
DBUG_PRINT("ha_federated::get_share",("share->select_query %s", share->select_query)); DBUG_PRINT("ha_federated::get_share",
("share->select_query %s", share->select_query));
if (my_hash_insert(&federated_open_tables, (byte*) share)) if (my_hash_insert(&federated_open_tables, (byte*) share))
goto error; goto error;
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);
} }
share->use_count++; share->use_count++;
pthread_mutex_unlock(&federated_mutex); pthread_mutex_unlock(&federated_mutex);
return share; return share;
error2:
thr_lock_delete(&share->lock);
pthread_mutex_destroy(&share->mutex);
error: error:
pthread_mutex_unlock(&federated_mutex); pthread_mutex_unlock(&federated_mutex);
if (share->scheme)
my_free((gptr) share->scheme, MYF(0));
VOID(pthread_mutex_destroy(&share->mutex));
my_free((gptr) share, MYF(0)); my_free((gptr) share, MYF(0));
return NULL; return NULL;
...@@ -827,11 +848,15 @@ error: ...@@ -827,11 +848,15 @@ error:
static int free_share(FEDERATED_SHARE *share) static int free_share(FEDERATED_SHARE *share)
{ {
pthread_mutex_lock(&federated_mutex); pthread_mutex_lock(&federated_mutex);
if (!--share->use_count) if (!--share->use_count)
{ {
if (share->scheme)
my_free((gptr) share->scheme, MYF(0));
hash_delete(&federated_open_tables, (byte*) share); hash_delete(&federated_open_tables, (byte*) share);
thr_lock_delete(&share->lock); thr_lock_delete(&share->lock);
pthread_mutex_destroy(&share->mutex); VOID(pthread_mutex_destroy(&share->mutex));
my_free((gptr) share, MYF(0)); my_free((gptr) share, MYF(0));
} }
pthread_mutex_unlock(&federated_mutex); pthread_mutex_unlock(&federated_mutex);
...@@ -847,7 +872,13 @@ static int free_share(FEDERATED_SHARE *share) ...@@ -847,7 +872,13 @@ static int free_share(FEDERATED_SHARE *share)
in handler.cc. in handler.cc.
*/ */
const char **ha_federated::bas_ext() const const char **ha_federated::bas_ext() const
{ static const char *ext[]= { NullS }; return ext; } {
static const char *ext[]=
{
NullS
};
return ext;
}
/* /*
...@@ -867,23 +898,22 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) ...@@ -867,23 +898,22 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
if (!(share= get_share(name, table))) if (!(share= get_share(name, table)))
DBUG_RETURN(1); DBUG_RETURN(1);
thr_lock_data_init(&share->lock,&lock,NULL); thr_lock_data_init(&share->lock, &lock, NULL);
/* Connect to remote database mysql_real_connect() */ /* Connect to remote database mysql_real_connect() */
mysql= mysql_init(0); mysql= mysql_init(0);
DBUG_PRINT("ha_federated::open",("hostname %s", share->hostname)); DBUG_PRINT("ha_federated::open", ("hostname %s", share->hostname));
DBUG_PRINT("ha_federated::open",("username %s", share->username)); DBUG_PRINT("ha_federated::open", ("username %s", share->username));
DBUG_PRINT("ha_federated::open",("password %s", share->password)); DBUG_PRINT("ha_federated::open", ("password %s", share->password));
DBUG_PRINT("ha_federated::open",("database %s", share->database)); DBUG_PRINT("ha_federated::open", ("database %s", share->database));
DBUG_PRINT("ha_federated::open",("port %d", share->port)); DBUG_PRINT("ha_federated::open", ("port %d", share->port));
if (!mysql_real_connect(mysql, if (!mysql_real_connect(mysql,
share->hostname, share->hostname,
share->username, share->username,
share->password, share->password,
share->database, share->database,
share->port, share->port,
NULL, share->socket, 0))
0))
{ {
my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql)); my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql));
DBUG_RETURN(ER_CONNECT_TO_MASTER); DBUG_RETURN(ER_CONNECT_TO_MASTER);
...@@ -905,6 +935,15 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) ...@@ -905,6 +935,15 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked)
int ha_federated::close(void) int ha_federated::close(void)
{ {
DBUG_ENTER("ha_federated::close"); DBUG_ENTER("ha_federated::close");
/* free the result set */
if (result)
{
DBUG_PRINT("ha_federated::close",
("mysql_free_result result at address %lx", result));
mysql_free_result(result);
result= 0;
}
/* Disconnect from mysql */ /* Disconnect from mysql */
mysql_close(mysql); mysql_close(mysql);
DBUG_RETURN(free_share(share)); DBUG_RETURN(free_share(share));
...@@ -929,10 +968,9 @@ int ha_federated::close(void) ...@@ -929,10 +968,9 @@ int ha_federated::close(void)
1 if NULL 1 if NULL
0 otherwise 0 otherwise
*/ */
inline uint field_in_record_is_null ( inline uint field_in_record_is_null(TABLE *table,
TABLE* table, /* in: MySQL table object */ Field *field,
Field* field, /* in: MySQL field object */ char *record)
char* record) /* in: a row in MySQL format */
{ {
int null_offset; int null_offset;
DBUG_ENTER("ha_federated::field_in_record_is_null"); DBUG_ENTER("ha_federated::field_in_record_is_null");
...@@ -940,7 +978,7 @@ inline uint field_in_record_is_null ( ...@@ -940,7 +978,7 @@ inline uint field_in_record_is_null (
if (!field->null_ptr) if (!field->null_ptr)
DBUG_RETURN(0); DBUG_RETURN(0);
null_offset= (uint) ((char*) field->null_ptr - (char*) table->record[0]); null_offset= (uint) ((char*)field->null_ptr - (char*)table->record[0]);
if (record[null_offset] & field->null_bit) if (record[null_offset] & field->null_bit)
DBUG_RETURN(1); DBUG_RETURN(1);
...@@ -961,59 +999,57 @@ inline uint field_in_record_is_null ( ...@@ -961,59 +999,57 @@ inline uint field_in_record_is_null (
Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc, Called from item_sum.cc, item_sum.cc, sql_acl.cc, sql_insert.cc,
sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc. sql_insert.cc, sql_select.cc, sql_table.cc, sql_udf.cc, and sql_update.cc.
*/ */
int ha_federated::write_row(byte * buf) int ha_federated::write_row(byte *buf)
{ {
int x= 0, num_fields= 0; uint x= 0, num_fields= 0;
Field **field; Field **field;
ulong current_query_id= 1; ulong current_query_id= 1;
ulong tmp_query_id= 1; ulong tmp_query_id= 1;
int all_fields_have_same_query_id= 1; uint all_fields_have_same_query_id= 1;
char insert_buffer[IO_SIZE]; char insert_buffer[IO_SIZE];
char values_buffer[IO_SIZE], insert_field_value_buffer[IO_SIZE]; char values_buffer[IO_SIZE], insert_field_value_buffer[IO_SIZE];
// The main insert query string /* The main insert query string */
String insert_string(insert_buffer, sizeof(insert_buffer), &my_charset_bin); String insert_string(insert_buffer, sizeof(insert_buffer), &my_charset_bin);
insert_string.length(0); insert_string.length(0);
// The string containing the values to be added to the insert /* The string containing the values to be added to the insert */
String values_string(values_buffer, sizeof(values_buffer), &my_charset_bin); String values_string(values_buffer, sizeof(values_buffer), &my_charset_bin);
values_string.length(0); values_string.length(0);
// The actual value of the field, to be added to the values_string /* The actual value of the field, to be added to the values_string */
String insert_field_value_string(insert_field_value_buffer, String insert_field_value_string(insert_field_value_buffer,
sizeof(insert_field_value_buffer), &my_charset_bin); sizeof(insert_field_value_buffer),
&my_charset_bin);
insert_field_value_string.length(0); insert_field_value_string.length(0);
DBUG_ENTER("ha_federated::write_row"); DBUG_ENTER("ha_federated::write_row");
/*
I want to use this and the next line, but the repository needs to be statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status);
updated to do so
*/
statistic_increment(table->in_use->status_var.ha_write_count,&LOCK_status);
if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT)
table->timestamp_field->set_time(); table->timestamp_field->set_time();
/* /*
get the current query id - the fields that we add to the insert get the current query id - the fields that we add to the insert
statement to send to the remote will not be appended unless they match statement to send to the remote will not be appended unless they match
this query id this query id
*/ */
current_query_id= table->in_use->query_id; current_query_id= table->in_use->query_id;
DBUG_PRINT("ha_federated::write_row", ("current query id %d", DBUG_PRINT("ha_federated::write_row", ("current query id %d",
current_query_id)); current_query_id));
// start off our string /* start off our string */
insert_string.append("INSERT INTO "); insert_string.append("INSERT INTO ");
insert_string.append(share->table_base_name); insert_string.append(share->table_base_name);
// start both our field and field values strings /* start both our field and field values strings */
insert_string.append(" ("); insert_string.append(" (");
values_string.append(" VALUES ("); values_string.append(" VALUES (");
/* /*
Even if one field is different, all_fields_same_query_id can't remain Even if one field is different, all_fields_same_query_id can't remain
0 if it remains 0, then that means no fields were specified in the query 0 if it remains 0, then that means no fields were specified in the query
such as in the case of INSERT INTO table VALUES (val1, val2, valN) such as in the case of INSERT INTO table VALUES (val1, val2, valN)
*/ */
for (field= table->field; *field ; field++, x++) for (field= table->field; *field; field++, x++)
{ {
if (x > 0 && tmp_query_id != (*field)->query_id) if (x > 0 && tmp_query_id != (*field)->query_id)
all_fields_have_same_query_id= 0; all_fields_have_same_query_id= 0;
...@@ -1021,18 +1057,18 @@ int ha_federated::write_row(byte * buf) ...@@ -1021,18 +1057,18 @@ int ha_federated::write_row(byte * buf)
tmp_query_id= (*field)->query_id; tmp_query_id= (*field)->query_id;
} }
/* /*
loop through the field pointer array, add any fields to both the values loop through the field pointer array, add any fields to both the values
list and the fields list that match the current query id list and the fields list that match the current query id
*/ */
for (field= table->field; *field ; field++, x++) for (field= table->field; *field; field++, x++)
{ {
DBUG_PRINT("ha_federated::write_row", ("field type %d", (*field)->type())); DBUG_PRINT("ha_federated::write_row", ("field type %d", (*field)->type()));
// if there is a query id and if it's equal to the current query id // if there is a query id and if it's equal to the current query id
if ( ((*field)->query_id && (*field)->query_id == current_query_id ) if (((*field)->query_id && (*field)->query_id == current_query_id)
|| all_fields_have_same_query_id) || all_fields_have_same_query_id)
{ {
num_fields++; num_fields++;
if ((*field)->is_null()) if ((*field)->is_null())
{ {
DBUG_PRINT("ha_federated::write_row", DBUG_PRINT("ha_federated::write_row",
...@@ -1046,64 +1082,60 @@ int ha_federated::write_row(byte * buf) ...@@ -1046,64 +1082,60 @@ int ha_federated::write_row(byte * buf)
("current query id %d field is not null query ID %d", ("current query id %d field is not null query ID %d",
current_query_id, (*field)->query_id)); current_query_id, (*field)->query_id));
(*field)->val_str(&insert_field_value_string); (*field)->val_str(&insert_field_value_string);
/* quote these fields if they require it */
(*field)->quote_data(&insert_field_value_string);
} }
// append the field name /* append the field name */
insert_string.append((*field)->field_name); insert_string.append((*field)->field_name);
// quote these fields if they require it /* append the value */
(*field)->quote_data(&insert_field_value_string);
// append the value
values_string.append(insert_field_value_string); values_string.append(insert_field_value_string);
insert_field_value_string.length(0); insert_field_value_string.length(0);
// append commas between both fields and fieldnames /* append commas between both fields and fieldnames */
insert_string.append(','); insert_string.append(',');
values_string.append(','); values_string.append(',');
DBUG_PRINT("ha_federated::write_row", DBUG_PRINT("ha_federated::write_row",
("insert_string %s values_string %s insert_field_value_string %s", ("insert_string %s values_string %s insert_field_value_string %s",
insert_string.c_ptr_quick(), values_string.c_ptr_quick(), insert_string.c_ptr_quick(), values_string.c_ptr_quick(),
insert_field_value_string.c_ptr_quick())); insert_field_value_string.c_ptr_quick()));
} }
} }
/* /*
chop of the trailing comma, or if there were no fields, a '(' chop of the trailing comma, or if there were no fields, a '('
So, "INSERT INTO foo (" becomes "INSERT INTO foo " So, "INSERT INTO foo (" becomes "INSERT INTO foo "
or, with fields, "INSERT INTO foo (field1, field2," becomes or, with fields, "INSERT INTO foo (field1, field2," becomes
"INSERT INTO foo (field1, field2" "INSERT INTO foo (field1, field2"
*/ */
insert_string.chop(); insert_string.chop();
/* /*
if there were no fields, we don't want to add a closing paren if there were no fields, we don't want to add a closing paren
AND, we don't want to chop off the last char '(' AND, we don't want to chop off the last char '('
insert will be "INSERT INTO t1 VALUES ();" insert will be "INSERT INTO t1 VALUES ();"
*/ */
DBUG_PRINT("ha_federated::write_row",("x %d num fields %d", DBUG_PRINT("ha_federated::write_row", ("x %d num fields %d", x, num_fields));
x, num_fields));
if (num_fields > 0) if (num_fields > 0)
{ {
// chops off leading commas /* chops off leading commas */
values_string.chop(); values_string.chop();
insert_string.append(')'); insert_string.append(')');
} }
// we always want to append this, even if there aren't any fields /* we always want to append this, even if there aren't any fields */
values_string.append(')'); values_string.append(')');
// add the values /* add the values */
insert_string.append(values_string); insert_string.append(values_string);
DBUG_PRINT("ha_federated::write_row",("insert query %s", DBUG_PRINT("ha_federated::write_row", ("insert query %s",
insert_string.c_ptr_quick())); insert_string.c_ptr_quick()));
if (mysql_real_query(mysql, insert_string.c_ptr_quick(), if (mysql_real_query(mysql, insert_string.ptr(), insert_string.length()))
insert_string.length()))
{ {
my_error(ER_QUERY_ON_MASTER,MYF(0),mysql_error(mysql)); my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
DBUG_RETURN(ER_QUERY_ON_MASTER); DBUG_RETURN(ER_QUERY_ON_MASTER);
} }
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -1125,27 +1157,28 @@ int ha_federated::write_row(byte * buf) ...@@ -1125,27 +1157,28 @@ int ha_federated::write_row(byte * buf)
Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc. Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc.
*/ */
int ha_federated::update_row( int ha_federated::update_row(const byte *old_data, byte *new_data)
const byte * old_data,
byte * new_data
)
{ {
int x= 0; uint x= 0;
uint has_a_primary_key= 0; uint has_a_primary_key= 0;
int primary_key_field_num; uint primary_key_field_num;
char old_field_value_buffer[IO_SIZE], new_field_value_buffer[IO_SIZE]; char old_field_value_buffer[IO_SIZE], new_field_value_buffer[IO_SIZE];
char update_buffer[IO_SIZE], where_buffer[IO_SIZE]; char update_buffer[IO_SIZE], where_buffer[IO_SIZE];
// stores the value to be replaced of the field were are updating /*
String old_field_value(old_field_value_buffer, sizeof(old_field_value_buffer), &my_charset_bin); stores the value to be replaced of the field were are updating
*/
String old_field_value(old_field_value_buffer, sizeof(old_field_value_buffer),
&my_charset_bin);
old_field_value.length(0); old_field_value.length(0);
// stores the new value of the field /* stores the new value of the field */
String new_field_value(new_field_value_buffer, sizeof(new_field_value_buffer), &my_charset_bin); String new_field_value(new_field_value_buffer, sizeof(new_field_value_buffer),
&my_charset_bin);
new_field_value.length(0); new_field_value.length(0);
// stores the update query /* stores the update query */
String update_string(update_buffer, sizeof(update_buffer), &my_charset_bin); String update_string(update_buffer, sizeof(update_buffer), &my_charset_bin);
update_string.length(0); update_string.length(0);
// stores the WHERE clause /* stores the WHERE clause */
String where_string(where_buffer, sizeof(where_buffer), &my_charset_bin); String where_string(where_buffer, sizeof(where_buffer), &my_charset_bin);
where_string.length(0); where_string.length(0);
...@@ -1153,10 +1186,10 @@ int ha_federated::update_row( ...@@ -1153,10 +1186,10 @@ int ha_federated::update_row(
has_a_primary_key= table->s->primary_key == 0 ? 1 : 0; has_a_primary_key= table->s->primary_key == 0 ? 1 : 0;
primary_key_field_num= has_a_primary_key ? primary_key_field_num= has_a_primary_key ?
table->key_info[table->s->primary_key].key_part->fieldnr -1 : -1; table->key_info[table->s->primary_key].key_part->fieldnr - 1 : -1;
if (has_a_primary_key) if (has_a_primary_key)
DBUG_PRINT("ha_federated::update_row", ("has a primary key")); DBUG_PRINT("ha_federated::update_row", ("has a primary key"));
update_string.append("UPDATE "); update_string.append("UPDATE ");
update_string.append(share->table_base_name); update_string.append(share->table_base_name);
...@@ -1171,19 +1204,19 @@ int ha_federated::update_row( ...@@ -1171,19 +1204,19 @@ int ha_federated::update_row(
used to create SET field=value and old data is used to create WHERE used to create SET field=value and old data is used to create WHERE
field=oldvalue field=oldvalue
*/ */
for (Field **field= table->field ; *field ; field++, x++) for (Field **field= table->field; *field; field++, x++)
{ {
/* /*
In all of these tests for 'has_a_primary_key', what I'm trying to In all of these tests for 'has_a_primary_key', what I'm trying to
accomplish is to only use the primary key in the WHERE clause if the accomplish is to only use the primary key in the WHERE clause if the
table has a primary key, as opposed to a table without a primary key table has a primary key, as opposed to a table without a primary key
in which case we have to use all the fields to create a WHERE clause in which case we have to use all the fields to create a WHERE clause
using the old/current values, as well as adding a LIMIT statement using the old/current values, as well as adding a LIMIT statement
*/ */
if (has_a_primary_key) if (has_a_primary_key)
{ {
if (x == primary_key_field_num) if (x == primary_key_field_num)
where_string.append((*field)->field_name); where_string.append((*field)->field_name);
} }
else else
...@@ -1200,61 +1233,59 @@ int ha_federated::update_row( ...@@ -1200,61 +1233,59 @@ int ha_federated::update_row(
(*field)->val_str(&new_field_value); (*field)->val_str(&new_field_value);
(*field)->quote_data(&new_field_value); (*field)->quote_data(&new_field_value);
if ( has_a_primary_key ) if (has_a_primary_key)
{ {
if (x == primary_key_field_num) if (x == primary_key_field_num)
where_string.append("="); where_string.append("=");
} }
else else if (!field_in_record_is_null(table, *field, (char*) old_data))
if (! field_in_record_is_null(table, *field, (char*) old_data)) where_string.append("=");
where_string.append("=");
} }
if ( has_a_primary_key) if (has_a_primary_key)
{ {
if (x == primary_key_field_num) if (x == primary_key_field_num)
{ {
(*field)->val_str(&old_field_value, (*field)->val_str(&old_field_value,
(char *)(old_data + (*field)->offset())); (char*) (old_data + (*field)->offset()));
(*field)->quote_data(&old_field_value); (*field)->quote_data(&old_field_value);
where_string.append(old_field_value); where_string.append(old_field_value);
} }
} }
else else
{ {
if (field_in_record_is_null(table, *field, (char*) old_data)) if (field_in_record_is_null(table, *field, (char*) old_data))
where_string.append(" IS NULL "); where_string.append(" IS NULL ");
else else
{ {
(*field)->val_str(&old_field_value, (*field)->val_str(&old_field_value,
(char *)(old_data + (*field)->offset())); (char*) (old_data + (*field)->offset()));
(*field)->quote_data(&old_field_value); (*field)->quote_data(&old_field_value);
where_string.append(old_field_value); where_string.append(old_field_value);
} }
} }
update_string.append(new_field_value); update_string.append(new_field_value);
new_field_value.length(0); new_field_value.length(0);
if ((uint) x+1 < table->s->fields) if (x + 1 < table->s->fields)
{ {
update_string.append(", "); update_string.append(", ");
if (! has_a_primary_key) if (!has_a_primary_key)
where_string.append(" AND "); where_string.append(" AND ");
} }
old_field_value.length(0); old_field_value.length(0);
} }
update_string.append(" WHERE "); update_string.append(" WHERE ");
update_string.append(where_string.c_ptr_quick()); update_string.append(where_string);
if (! has_a_primary_key) if (! has_a_primary_key)
update_string.append(" LIMIT 1"); update_string.append(" LIMIT 1");
DBUG_PRINT("ha_federated::update_row", ("Final update query: %s", DBUG_PRINT("ha_federated::update_row", ("Final update query: %s",
update_string.c_ptr_quick())); update_string.c_ptr_quick()));
if (mysql_real_query(mysql, update_string.c_ptr_quick(), if (mysql_real_query(mysql, update_string.ptr(), update_string.length()))
update_string.length()))
{ {
my_error(ER_QUERY_ON_MASTER,MYF(0),mysql_error(mysql)); my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
DBUG_RETURN(ER_QUERY_ON_MASTER); DBUG_RETURN(ER_QUERY_ON_MASTER);
} }
...@@ -1275,9 +1306,9 @@ int ha_federated::update_row( ...@@ -1275,9 +1306,9 @@ int ha_federated::update_row(
it is used for removing duplicates while in insert it is used for REPLACE it is used for removing duplicates while in insert it is used for REPLACE
calls. calls.
*/ */
int ha_federated::delete_row(const byte * buf) int ha_federated::delete_row(const byte *buf)
{ {
int x= 0; uint x= 0;
char delete_buffer[IO_SIZE]; char delete_buffer[IO_SIZE];
char data_buffer[IO_SIZE]; char data_buffer[IO_SIZE];
...@@ -1292,7 +1323,7 @@ int ha_federated::delete_row(const byte * buf) ...@@ -1292,7 +1323,7 @@ int ha_federated::delete_row(const byte * buf)
delete_string.append(share->table_base_name); delete_string.append(share->table_base_name);
delete_string.append(" WHERE "); delete_string.append(" WHERE ");
for (Field **field= table->field; *field; field++, x++) for (Field **field= table->field; *field; field++, x++)
{ {
delete_string.append((*field)->field_name); delete_string.append((*field)->field_name);
...@@ -1307,22 +1338,21 @@ int ha_federated::delete_row(const byte * buf) ...@@ -1307,22 +1338,21 @@ int ha_federated::delete_row(const byte * buf)
(*field)->val_str(&data_string); (*field)->val_str(&data_string);
(*field)->quote_data(&data_string); (*field)->quote_data(&data_string);
} }
delete_string.append(data_string); delete_string.append(data_string);
data_string.length(0); data_string.length(0);
if ((uint) x+1 < table->s->fields) if (x + 1 < table->s->fields)
delete_string.append(" AND "); delete_string.append(" AND ");
} }
delete_string.append(" LIMIT 1"); delete_string.append(" LIMIT 1");
DBUG_PRINT("ha_federated::delete_row", DBUG_PRINT("ha_federated::delete_row",
("Delete sql: %s", delete_string.c_ptr_quick())); ("Delete sql: %s", delete_string.c_ptr_quick()));
if ( mysql_real_query(mysql, delete_string.c_ptr_quick(), if (mysql_real_query(mysql, delete_string.ptr(), delete_string.length()))
delete_string.length()))
{ {
my_error(ER_QUERY_ON_MASTER,MYF(0),mysql_error(mysql)); my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
DBUG_RETURN(ER_QUERY_ON_MASTER); DBUG_RETURN(ER_QUERY_ON_MASTER);
} }
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -1335,10 +1365,10 @@ int ha_federated::delete_row(const byte * buf) ...@@ -1335,10 +1365,10 @@ int ha_federated::delete_row(const byte * buf)
index. This method, which is called in the case of an SQL statement having index. This method, which is called in the case of an SQL statement having
a WHERE clause on a non-primary key index, simply calls index_read_idx. a WHERE clause on a non-primary key index, simply calls index_read_idx.
*/ */
int ha_federated::index_read(byte * buf, const byte * key, int ha_federated::index_read(byte *buf, const byte *key,
uint key_len __attribute__((unused)), uint key_len __attribute__ ((unused)),
enum ha_rkey_function find_flag enum ha_rkey_function find_flag
__attribute__((unused))) __attribute__ ((unused)))
{ {
DBUG_ENTER("ha_federated::index_read"); DBUG_ENTER("ha_federated::index_read");
DBUG_RETURN(index_read_idx(buf, active_index, key, key_len, find_flag)); DBUG_RETURN(index_read_idx(buf, active_index, key, key_len, find_flag));
...@@ -1353,10 +1383,10 @@ int ha_federated::index_read(byte * buf, const byte * key, ...@@ -1353,10 +1383,10 @@ int ha_federated::index_read(byte * buf, const byte * key,
a regular non-primary key index, OR is called DIRECTLY when the WHERE clause a regular non-primary key index, OR is called DIRECTLY when the WHERE clause
uses a PRIMARY KEY index. uses a PRIMARY KEY index.
*/ */
int ha_federated::index_read_idx(byte * buf, uint index, const byte * key, int ha_federated::index_read_idx(byte *buf, uint index, const byte *key,
uint key_len __attribute__((unused)), uint key_len __attribute__ ((unused)),
enum ha_rkey_function find_flag enum ha_rkey_function find_flag
__attribute__((unused))) __attribute__ ((unused)))
{ {
char index_value[IO_SIZE]; char index_value[IO_SIZE];
char key_value[IO_SIZE]; char key_value[IO_SIZE];
...@@ -1370,27 +1400,34 @@ int ha_federated::index_read_idx(byte * buf, uint index, const byte * key, ...@@ -1370,27 +1400,34 @@ int ha_federated::index_read_idx(byte * buf, uint index, const byte * key,
sql_query.length(0); sql_query.length(0);
DBUG_ENTER("ha_federated::index_read_idx"); DBUG_ENTER("ha_federated::index_read_idx");
statistic_increment(table->in_use->status_var.ha_read_key_count,&LOCK_status); statistic_increment(table->in_use->status_var.ha_read_key_count,
&LOCK_status);
sql_query.append(share->select_query); sql_query.append(share->select_query);
sql_query.append(" WHERE "); sql_query.append(" WHERE ");
keylen= strlen((char *)(key)); keylen= strlen((char*) (key));
create_where_from_key(&index_string, &table->key_info[index], key, keylen); create_where_from_key(&index_string, &table->key_info[index], key, keylen);
sql_query.append(index_string); sql_query.append(index_string);
DBUG_PRINT("ha_federated::index_read_idx", DBUG_PRINT("ha_federated::index_read_idx",
("current key %d key value %s index_string value %s length %d", index, (char *)(key),index_string.c_ptr_quick(), ("current key %d key value %s index_string value %s length %d",
index_string.length())); index, (char*) key, index_string.c_ptr_quick(),
index_string.length()));
DBUG_PRINT("ha_federated::index_read_idx", DBUG_PRINT("ha_federated::index_read_idx",
("current position %d sql_query %s", current_position, ("current position %d sql_query %s", current_position,
sql_query.c_ptr_quick())); sql_query.c_ptr_quick()));
if (mysql_real_query(mysql, sql_query.c_ptr_quick(), sql_query.length())) if (result)
{
mysql_free_result(result);
result= 0;
}
if (mysql_real_query(mysql, sql_query.ptr(), sql_query.length()))
{ {
my_error(ER_QUERY_ON_MASTER,MYF(0),mysql_error(mysql)); my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
DBUG_RETURN(ER_QUERY_ON_MASTER); DBUG_RETURN(ER_QUERY_ON_MASTER);
} }
result= mysql_store_result(mysql); result= mysql_store_result(mysql);
...@@ -1403,7 +1440,7 @@ int ha_federated::index_read_idx(byte * buf, uint index, const byte * key, ...@@ -1403,7 +1440,7 @@ int ha_federated::index_read_idx(byte * buf, uint index, const byte * key,
if (mysql_errno(mysql)) if (mysql_errno(mysql))
{ {
table->status= STATUS_NOT_FOUND; table->status= STATUS_NOT_FOUND;
DBUG_RETURN(mysql_errno(mysql)); DBUG_RETURN(mysql_errno(mysql));
} }
DBUG_RETURN(rnd_next(buf)); DBUG_RETURN(rnd_next(buf));
...@@ -1425,7 +1462,7 @@ int ha_federated::index_init(uint keynr) ...@@ -1425,7 +1462,7 @@ int ha_federated::index_init(uint keynr)
/* /*
Used to read forward through the index. Used to read forward through the index.
*/ */
int ha_federated::index_next(byte * buf) int ha_federated::index_next(byte *buf)
{ {
DBUG_ENTER("ha_federated::index_next"); DBUG_ENTER("ha_federated::index_next");
DBUG_RETURN(rnd_next(buf)); DBUG_RETURN(rnd_next(buf));
...@@ -1449,23 +1486,54 @@ int ha_federated::rnd_init(bool scan) ...@@ -1449,23 +1486,54 @@ int ha_federated::rnd_init(bool scan)
DBUG_ENTER("ha_federated::rnd_init"); DBUG_ENTER("ha_federated::rnd_init");
int num_fields, rows; int num_fields, rows;
DBUG_PRINT("ha_federated::rnd_init", /*
("share->select_query %s", share->select_query)); This 'scan' flag is incredibly important for this handler to work properly,
if (mysql_real_query(mysql, share->select_query, strlen(share->select_query))) especially with updates that are called with indexes, because what happens
without this is index_read_idx gets called, does a query using the
index in a where clause, calls mysql_store_result, which then rnd_init
(from sql_update.cc) is called after this, which would do a
"select * from table" then a mysql_store_result, wiping out the result
set from index_read_idx's query, which causes the subsequent update_row
to update the wrong row!
*/
scan_flag= scan;
if (scan)
{ {
my_error(ER_QUERY_ON_MASTER,MYF(0),mysql_error(mysql)); DBUG_PRINT("ha_federated::rnd_init",
DBUG_RETURN(ER_QUERY_ON_MASTER); ("share->select_query %s", share->select_query));
} if (result)
result= mysql_store_result(mysql); {
DBUG_PRINT("ha_federated::rnd_init",
("mysql_free_result address %lx", result));
mysql_free_result(result);
result= 0;
}
if (mysql_errno(mysql)) if (mysql_real_query
DBUG_RETURN(mysql_errno(mysql)); (mysql, share->select_query, strlen(share->select_query)))
{
my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
DBUG_RETURN(ER_QUERY_ON_MASTER);
}
result= mysql_store_result(mysql);
if (mysql_errno(mysql))
DBUG_RETURN(mysql_errno(mysql));
}
DBUG_RETURN(0); DBUG_RETURN(0);
} }
int ha_federated::rnd_end() int ha_federated::rnd_end()
{ {
DBUG_ENTER("ha_federated::rnd_end"); DBUG_ENTER("ha_federated::rnd_end");
if (result)
{
DBUG_PRINT("ha_federated::index_end",
("mysql_free_result address %lx", result));
mysql_free_result(result);
result= 0;
}
mysql_free_result(result); mysql_free_result(result);
DBUG_RETURN(index_end()); DBUG_RETURN(index_end());
} }
...@@ -1493,10 +1561,12 @@ int ha_federated::rnd_next(byte *buf) ...@@ -1493,10 +1561,12 @@ int ha_federated::rnd_next(byte *buf)
// Fetch a row, insert it back in a row format. // Fetch a row, insert it back in a row format.
current_position= result->data_cursor; current_position= result->data_cursor;
if (! (row= mysql_fetch_row(result))) DBUG_PRINT("ha_federated::rnd_next",
("current position %d", current_position));
if (!(row= mysql_fetch_row(result)))
DBUG_RETURN(HA_ERR_END_OF_FILE); DBUG_RETURN(HA_ERR_END_OF_FILE);
DBUG_RETURN(convert_row_to_internal_format(buf,row)); DBUG_RETURN(convert_row_to_internal_format(buf, row));
} }
...@@ -1517,7 +1587,7 @@ void ha_federated::position(const byte *record) ...@@ -1517,7 +1587,7 @@ void ha_federated::position(const byte *record)
{ {
DBUG_ENTER("ha_federated::position"); DBUG_ENTER("ha_federated::position");
//my_store_ptr Add seek storage //my_store_ptr Add seek storage
*(MYSQL_ROW_OFFSET *)ref=current_position; // ref is always aligned *(MYSQL_ROW_OFFSET *) ref= current_position; // ref is always aligned
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1532,14 +1602,25 @@ void ha_federated::position(const byte *record) ...@@ -1532,14 +1602,25 @@ void ha_federated::position(const byte *record)
Called from filesort.cc records.cc sql_insert.cc sql_select.cc sql_update.cc. 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 ha_federated::rnd_pos(byte *buf, byte *pos)
{ {
DBUG_ENTER("ha_federated::rnd_pos"); DBUG_ENTER("ha_federated::rnd_pos");
statistic_increment(table->in_use->status_var.ha_read_rnd_count,&LOCK_status); /*
memcpy_fixed(&current_position, pos, sizeof(MYSQL_ROW_OFFSET)); // pos is not aligned we do not need to do any of this if there has been a scan performed already, or
result->current_row= 0; if this is an update and index_read_idx already has a result set in which to build
result->data_cursor= current_position; it's update query from
DBUG_RETURN(rnd_next(buf)); */
if (scan_flag)
{
statistic_increment(table->in_use->status_var.ha_read_rnd_count,
&LOCK_status);
memcpy_fixed(&current_position, pos, sizeof(MYSQL_ROW_OFFSET)); // pos
/* is not aligned */
result->current_row= 0;
result->data_cursor= current_position;
DBUG_RETURN(rnd_next(buf));
}
DBUG_RETURN(0);
} }
...@@ -1586,11 +1667,11 @@ int ha_federated::rnd_pos(byte * buf, byte *pos) ...@@ -1586,11 +1667,11 @@ int ha_federated::rnd_pos(byte * buf, byte *pos)
sql_update.cc sql_update.cc
*/ */
// FIX: later version provide better information to the optimizer /* FIX: later version provide better information to the optimizer */
void ha_federated::info(uint flag) void ha_federated::info(uint flag)
{ {
DBUG_ENTER("ha_federated::info"); DBUG_ENTER("ha_federated::info");
records= 10000; // Fake! records= 10000; // fix later
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1618,9 +1699,10 @@ int ha_federated::delete_all_rows() ...@@ -1618,9 +1699,10 @@ int ha_federated::delete_all_rows()
query.append("TRUNCATE "); query.append("TRUNCATE ");
query.append(share->table_base_name); query.append(share->table_base_name);
if (mysql_real_query(mysql, query.c_ptr_quick(), query.length())) { if (mysql_real_query(mysql, query.ptr(), query.length()))
my_error(ER_QUERY_ON_MASTER,MYF(0),mysql_error(mysql)); {
DBUG_RETURN(ER_QUERY_ON_MASTER); my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
DBUG_RETURN(ER_QUERY_ON_MASTER);
} }
DBUG_RETURN(HA_ERR_WRONG_COMMAND); DBUG_RETURN(HA_ERR_WRONG_COMMAND);
...@@ -1657,32 +1739,31 @@ int ha_federated::delete_all_rows() ...@@ -1657,32 +1739,31 @@ int ha_federated::delete_all_rows()
Called from lock.cc by get_lock_data(). Called from lock.cc by get_lock_data().
*/ */
THR_LOCK_DATA **ha_federated::store_lock(THD *thd, THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
THR_LOCK_DATA **to, THR_LOCK_DATA **to,
enum thr_lock_type lock_type) enum thr_lock_type lock_type)
{ {
if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
{ {
/* /*
Here is where we get into the guts of a row level lock. Here is where we get into the guts of a row level lock.
If TL_UNLOCK is set If TL_UNLOCK is set
If we are not doing a LOCK TABLE or DISCARD/IMPORT If we are not doing a LOCK TABLE or DISCARD/IMPORT
TABLESPACE, then allow multiple writers TABLESPACE, then allow multiple writers
*/ */
if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && if ((lock_type >= TL_WRITE_CONCURRENT_INSERT &&
lock_type <= TL_WRITE) && !thd->in_lock_tables lock_type <= TL_WRITE) && !thd->in_lock_tables && !thd->tablespace_op)
&& !thd->tablespace_op)
lock_type= TL_WRITE_ALLOW_WRITE; lock_type= TL_WRITE_ALLOW_WRITE;
/* /*
In queries of type INSERT INTO t1 SELECT ... FROM t2 ... In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
MySQL would use the lock TL_READ_NO_INSERT on t2, and that MySQL would use the lock TL_READ_NO_INSERT on t2, and that
would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
to t2. Convert the lock to a normal read lock to allow to t2. Convert the lock to a normal read lock to allow
concurrent inserts to t2. concurrent inserts to t2.
*/ */
if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables) if (lock_type == TL_READ_NO_INSERT && !thd->in_lock_tables)
lock_type= TL_READ; lock_type= TL_READ;
lock.type= lock_type; lock.type= lock_type;
...@@ -1699,19 +1780,16 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd, ...@@ -1699,19 +1780,16 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
create tables if they do not exist. create tables if they do not exist.
*/ */
int ha_federated::create(const char *name, TABLE *table_arg, int ha_federated::create(const char *name, TABLE *table_arg,
HA_CREATE_INFO *create_info) HA_CREATE_INFO *create_info)
{ {
int retcode;
FEDERATED_SHARE tmp; FEDERATED_SHARE tmp;
DBUG_ENTER("ha_federated::create"); DBUG_ENTER("ha_federated::create");
retcode= parse_url(&tmp, table_arg, 1); if (parse_url(&tmp, table_arg, 1))
if (retcode < 0)
{ {
DBUG_PRINT("ha_federated::create", my_error(ER_CANT_CREATE_TABLE, MYF(0));
("ERROR: on table creation for %s called parse_url, retcode %d",
create_info->data_file_name, retcode));
DBUG_RETURN(ER_CANT_CREATE_TABLE); DBUG_RETURN(ER_CANT_CREATE_TABLE);
} }
my_free((gptr) tmp.scheme, MYF(0));
DBUG_RETURN(0); DBUG_RETURN(0);
} }
#endif /* HAVE_FEDERATED_DB */ #endif /* HAVE_FEDERATED_DB */
...@@ -32,13 +32,16 @@ ...@@ -32,13 +32,16 @@
FEDERATED_SHARE is a structure that will be shared amoung all open handlers FEDERATED_SHARE is a structure that will be shared amoung all open handlers
The example implements the minimum of what you will probably need. The example implements the minimum of what you will probably need.
*/ */
//FIX document
typedef struct st_federated_share { typedef struct st_federated_share {
char *table_name; char *table_name;
char *table_base_name; char *table_base_name;
// the primary select query to be used in rnd_init /*
the primary select query to be used in rnd_init
*/
char *select_query; char *select_query;
// remote host info, parse_url supplies /*
remote host info, parse_url supplies
*/
char *scheme; char *scheme;
char *hostname; char *hostname;
char *username; char *username;
...@@ -62,6 +65,7 @@ class ha_federated: public handler ...@@ -62,6 +65,7 @@ class ha_federated: public handler
FEDERATED_SHARE *share; /* Shared lock info */ FEDERATED_SHARE *share; /* Shared lock info */
MYSQL *mysql; MYSQL *mysql;
MYSQL_RES *result; MYSQL_RES *result;
bool scan_flag;
uint ref_length; uint ref_length;
uint fetch_num; // stores the fetch num uint fetch_num; // stores the fetch num
MYSQL_ROW_OFFSET current_position; // Current position used by ::position() MYSQL_ROW_OFFSET current_position; // Current position used by ::position()
...@@ -73,10 +77,12 @@ private: ...@@ -73,10 +77,12 @@ private:
*/ */
uint convert_row_to_internal_format(byte *buf, MYSQL_ROW row); uint convert_row_to_internal_format(byte *buf, MYSQL_ROW row);
bool create_where_from_key(String *to, KEY *key_info, const byte *key, uint key_length); bool create_where_from_key(String *to, KEY *key_info, const byte *key, uint key_length);
bool create_where_from_key(String *to, KEY *key_info,
const byte *key, uint key_length);
public: public:
ha_federated(TABLE *table): handler(table), ha_federated(TABLE *table): handler(table),
mysql(0), mysql(0), result(0), scan_flag(0),
ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0) ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0)
{ {
} }
...@@ -126,11 +132,16 @@ public: ...@@ -126,11 +132,16 @@ public:
/* /*
Called in test_quick_select to determine if indexes should be used. Called in test_quick_select to determine if indexes should be used.
*/ */
virtual double scan_time() { DBUG_PRINT("ha_federated::scan_time", ("rows %d", records)); return (double)(records*2); } virtual double scan_time()
{
DBUG_PRINT("ha_federated::scan_time",
("rows %d", records)); return (double)(records*2);
}
/* /*
The next method will never be called if you do not implement indexes. The next method will never be called if you do not implement indexes.
*/ */
virtual double read_time(uint index, uint ranges, ha_rows rows) { return (double) rows / 20.0+1; } virtual double read_time(uint index, uint ranges, ha_rows rows)
{ return (double) rows / 20.0+1; }
/* /*
Everything below are methods that we implment in ha_federated.cc. Everything below are methods that we implment in ha_federated.cc.
...@@ -173,3 +184,6 @@ public: ...@@ -173,3 +184,6 @@ public:
THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to, THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
enum thr_lock_type lock_type); //required enum thr_lock_type lock_type); //required
}; };
bool federated_db_init(void);
bool federated_db_end(void);
...@@ -395,6 +395,16 @@ int ha_init() ...@@ -395,6 +395,16 @@ int ha_init()
ha_was_inited_ok(ht++); ha_was_inited_ok(ht++);
} }
#endif #endif
#ifdef HAVE_FEDERATED_DB
if (have_federated_db == SHOW_OPTION_YES)
{
if (federated_db_init())
{
have_federated_db= SHOW_OPTION_DISABLED;
error= 1;
}
}
#endif
#ifdef HAVE_ARCHIVE_DB #ifdef HAVE_ARCHIVE_DB
if (have_archive_db == SHOW_OPTION_YES) if (have_archive_db == SHOW_OPTION_YES)
{ {
...@@ -441,6 +451,10 @@ int ha_panic(enum ha_panic_function flag) ...@@ -441,6 +451,10 @@ int ha_panic(enum ha_panic_function flag)
if (have_ndbcluster == SHOW_OPTION_YES) if (have_ndbcluster == SHOW_OPTION_YES)
error|=ndbcluster_end(); error|=ndbcluster_end();
#endif #endif
#ifdef HAVE_FEDERATED_DB
if (have_federated_db == SHOW_OPTION_YES)
error|= federated_db_end();
#endif
#ifdef HAVE_ARCHIVE_DB #ifdef HAVE_ARCHIVE_DB
if (have_archive_db == SHOW_OPTION_YES) if (have_archive_db == SHOW_OPTION_YES)
error|= archive_db_end(); error|= archive_db_end();
......
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