diff options
-rw-r--r-- | include/mysql.h | 2 | ||||
-rw-r--r-- | mysql-test/r/federated.result | 26 | ||||
-rw-r--r-- | mysql-test/t/federated.test | 33 | ||||
-rw-r--r-- | sql-common/client.c | 2 | ||||
-rw-r--r-- | sql/ha_federated.cc | 698 | ||||
-rwxr-xr-x | sql/ha_federated.h | 3 |
6 files changed, 432 insertions, 332 deletions
diff --git a/include/mysql.h b/include/mysql.h index b87b865608e..e37cf710817 100644 --- a/include/mysql.h +++ b/include/mysql.h @@ -499,6 +499,8 @@ MYSQL_FIELD_OFFSET STDCALL mysql_field_seek(MYSQL_RES *result, MYSQL_FIELD_OFFSET offset); MYSQL_ROW STDCALL mysql_fetch_row(MYSQL_RES *result); unsigned long * STDCALL mysql_fetch_lengths(MYSQL_RES *result); +void STDCALL cli_fetch_lengths(ulong *to, MYSQL_ROW column, + unsigned int field_count); MYSQL_FIELD * STDCALL mysql_fetch_field(MYSQL_RES *result); MYSQL_RES * STDCALL mysql_list_fields(MYSQL *mysql, const char *table, const char *wild); diff --git a/mysql-test/r/federated.result b/mysql-test/r/federated.result index 4ed0b45a4c5..d1ad9921865 100644 --- a/mysql-test/r/federated.result +++ b/mysql-test/r/federated.result @@ -644,14 +644,19 @@ select * from federated.t1 where fileguts = 'jimbob'; id code fileguts creation_date entered_time 3 DEUEUEUEUEUEUEUEUEU jimbob 2004-04-04 04:04:04 2004-04-04 04:04:04 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; -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); +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; +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; Warnings: Note 1051 Unknown table 'countries' @@ -661,6 +666,13 @@ insert into federated.countries (country) values ('Germany'); insert into federated.countries (country) values ('Italy'); insert into federated.countries (country) values ('Finland'); 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; id country_id name other country 1 1 Kumar 11111 India diff --git a/mysql-test/t/federated.test b/mysql-test/t/federated.test index 413509a0a6a..c634badf04e 100644 --- a/mysql-test/t/federated.test +++ b/mysql-test/t/federated.test @@ -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', 'jimbob', '2004-04-04 04:04:04'); select * from federated.t1; -select * from federated.t1 where fileguts = 'jimbob'; # 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 # @@ -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)); 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; CREATE TABLE federated.countries ( `id` int(20) NOT NULL auto_increment, `country` varchar(32), primary key (id)); insert into federated.countries (country) values ('India'); @@ -576,6 +581,14 @@ insert into federated.countries (country) values ('Italy'); insert into federated.countries (country) values ('Finland'); 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; drop table federated.countries; diff --git a/sql-common/client.c b/sql-common/client.c index 9dcf6b3e32c..3d760c73eea 100644 --- a/sql-common/client.c +++ b/sql-common/client.c @@ -1121,7 +1121,7 @@ void mysql_read_default_options(struct st_mysql_options *options, 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) { ulong *prev_length; diff --git a/sql/ha_federated.cc b/sql/ha_federated.cc index 695c71677c0..eed145203c3 100644 --- a/sql/ha_federated.cc +++ b/sql/ha_federated.cc @@ -343,10 +343,10 @@ ./sql/ha_federated.cc ./sql/ha_federated.h -*/ +*/ #ifdef __GNUC__ -#pragma implementation // gcc: Class implementation +#pragma implementation // gcc: Class implementation #endif #include <mysql_priv.h> @@ -355,18 +355,21 @@ #include "ha_federated.h" #define MAX_REMOTE_SIZE IO_SIZE /* Variables for federated share methods */ -static HASH federated_open_tables; // Hash used to track open tables -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 +static HASH federated_open_tables; // Hash used to track open + // tables +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. */ -static byte* federated_get_key(FEDERATED_SHARE *share,uint *length, - my_bool not_used __attribute__((unused))) +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; + return (byte *) share->table_name; } /* @@ -374,8 +377,9 @@ static byte* federated_get_key(FEDERATED_SHARE *share,uint *length, SYNOPSIS parse_url() - share pointer to FEDERATED share - table pointer to current TABLE class + share pointer to FEDERATED share + table pointer to current TABLE class + table_create_flag determines what error to throw DESCRIPTION populates the share with information about the connection @@ -385,10 +389,10 @@ static byte* federated_get_key(FEDERATED_SHARE *share,uint *length, This string MUST be in the format of any of these: -scheme://username:password@hostname:port/database/table -scheme://username@hostname/database/table -scheme://username@hostname:port/database/table -scheme://username:password@hostname/database/table + scheme://username:password@hostname:port/database/table + scheme://username@hostname/database/table + scheme://username@hostname:port/database/table + scheme://username:password@hostname/database/table An Example: @@ -401,33 +405,34 @@ scheme://username:password@hostname/database/table RETURN VALUE 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"); // This either get set or will remain the same. 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)); - 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) { DBUG_PRINT("ha_federated::parse_url", ("The federated handler currently only supports connecting\ to a MySQL database!!!\n")); my_error(error_num, MYF(0), - "ERROR: federated handler only supports remote 'mysql://' database"); - DBUG_RETURN(-1); + "ERROR: federated handler only supports remote 'mysql://' database"); + DBUG_RETURN(1); } - share->username+= 3; + share->username += 3; if ((share->hostname= strchr(share->username, '@'))) { @@ -445,14 +450,14 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, uint table_create_fla DBUG_PRINT("ha_federated::parse_url", ("this connection string is not in the correct format!!!\n")); my_error(error_num, MYF(0), - "this connection string is not in the correct format!!!\n"); - DBUG_RETURN(-1); + "this connection string is not in the correct format!!!\n"); + DBUG_RETURN(1); } /* - Found that if the string is: -user:@hostname:port/database/table -Then password is a null string, so set to NULL - */ + Found that if the string is: + user:@hostname:port/database/table + Then password is a null string, so set to NULL + */ if ((share->password[0] == '\0')) share->password= NULL; } @@ -465,8 +470,8 @@ Then password is a null string, so set to NULL DBUG_PRINT("ha_federated::parse_url", ("this connection string is not in the correct format!!!\n")); my_error(error_num, MYF(0), - "this connection string is not in the correct format!!!\n"); - DBUG_RETURN(-1); + "this connection string is not in the correct format!!!\n"); + DBUG_RETURN(1); } if ((share->database= strchr(share->hostname, '/'))) @@ -494,8 +499,8 @@ Then password is a null string, so set to NULL DBUG_PRINT("ha_federated::parse_url", ("this connection string is not in the correct format!!!\n")); my_error(error_num, MYF(0), - "this connection string is not in the correct format!!!\n"); - DBUG_RETURN(-1); + "this connection string is not in the correct format!!!\n"); + DBUG_RETURN(1); } } else @@ -503,8 +508,8 @@ Then password is a null string, so set to NULL DBUG_PRINT("ha_federated::parse_url", ("this connection string is not in the correct format!!!\n")); my_error(error_num, MYF(0), - "this connection string is not in the correct format!!!\n"); - DBUG_RETURN(-1); + "this connection string is not in the correct format!!!\n"); + DBUG_RETURN(1); } // make sure there's not an extra / if ((strchr(share->table_base_name, '/'))) @@ -512,34 +517,40 @@ Then password is a null string, so set to NULL DBUG_PRINT("ha_federated::parse_url", ("this connection string is not in the correct format!!!\n")); my_error(error_num, MYF(0), - "this connection string is not in the correct format!!!\n"); - DBUG_RETURN(-1); + "this connection string is not in the correct format!!!\n"); + DBUG_RETURN(1); } if (share->hostname[0] == '\0') share->hostname= NULL; - 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)); + 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::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 { DBUG_PRINT("ha_federated::parse_url", - ("this connection string is not in the correct format!!!\n")); + ("this connection string is not in the correct format!!!\n")); my_error(error_num, MYF(0), - "this connection string is not in the correct format!!!\n"); - DBUG_RETURN(-1); + "this connection string is not in the correct format!!!\n"); + DBUG_RETURN(1); } } else - { + { DBUG_PRINT("ha_federated::parse_url", - ("this connection string is not in the correct format!!!\n")); + ("this connection string is not in the correct format!!!\n")); my_error(error_num, MYF(0), - "this connection string is not in the correct format!!!\n"); - DBUG_RETURN(-1); + "this connection string is not in the correct format!!!\n"); + DBUG_RETURN(1); } DBUG_RETURN(0); } @@ -564,24 +575,36 @@ Then password is a null string, so set to NULL */ uint ha_federated::convert_row_to_internal_format(byte *record, MYSQL_ROW row) { - unsigned long len; - int x= 0; + unsigned long *lengths; + unsigned int num_fields; + unsigned int x= 0; + DBUG_ENTER("ha_federated::convert_row_to_internal_format"); - // Question this - memset(record, 0, table->s->null_bytes); + num_fields= mysql_num_fields(result); + lengths= (unsigned long*) my_malloc(num_fields * sizeof(unsigned long), + MYF(0)); + cli_fetch_lengths((unsigned long*) (lengths), row, num_fields); - for (Field **field=table->field; *field ; field++, x++) + memset(record, 0, table->s->null_bytes); + + for (Field ** field= table->field; *field; field++, x++) { - if (!row[x]) + if (!row[x]) + { (*field)->set_null(); + } else /* - changed system_charset_info to default_charset_info because - testing revealed that german text was not being retrieved properly + 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); + DBUG_PRINT("ha_federated::convert_row_to_internal_format", + ("row[%d] %s length %lu", x, row[x], lengths[x])); + (*field)->store(row[x], lengths[x], &my_charset_bin); } + my_free((gptr) lengths, MYF(0)); + lengths= 0; DBUG_RETURN(0); } @@ -595,29 +618,30 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info, String tmp; 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; needs_quotes= field->needs_quotes(); //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; - if (second_loop++ && to->append(" AND ",5)) + if (second_loop++ && to->append(" AND ", 5)) DBUG_RETURN(1); - if (to->append('`') || to->append(field->field_name) || - to->append("` ",2)) - DBUG_RETURN(1); // Out of memory + if (to->append('`') || to->append(field->field_name) || to->append("` ", 2)) + DBUG_RETURN(1); // Out of memory if (key_part->null_bit) { if (*key++) { - if (to->append("IS NULL",7)) - DBUG_PRINT("ha_federated::create_where_from_key", ("NULL type %s", to->c_ptr_quick())); - DBUG_RETURN(1); - key_length-= key_part->store_length; - key+= key_part->store_length-1; + if (to->append("IS NULL", 7)) + DBUG_PRINT("ha_federated::create_where_from_key", + ("NULL type %s", to->c_ptr_quick())); + DBUG_RETURN(1); + key_length -= key_part->store_length; + key += key_part->store_length - 1; continue; } key_length--; @@ -630,101 +654,81 @@ bool ha_federated::create_where_from_key(String *to, KEY *key_info, { /* This is can be threated as a hex string */ Field_bit *field= (Field_bit *) (key_part->field); - char buff[64+2], *ptr; - byte *end= (byte *)(key) + length; + char buff[64 + 2], *ptr; + byte *end= (byte *) (key) + length; - buff[0]='0'; - buff[1]='x'; - for (ptr= buff+2 ; key < end ; key++) + buff[0]= '0'; + buff[1]= 'x'; + for (ptr= buff + 2; key < end; key++) { - uint tmp= (uint) (uchar) *key; - *ptr++=_dig_vec_upper[tmp >> 4]; - *ptr++=_dig_vec_upper[tmp & 15]; + uint tmp= (uint) (uchar) * key; + *ptr++= _dig_vec_upper[tmp >> 4]; + *ptr++= _dig_vec_upper[tmp & 15]; } - if (to->append(buff, (uint) (ptr-buff))) + if (to->append(buff, (uint) (ptr - buff))) DBUG_RETURN(1); - DBUG_PRINT("ha_federated::create_where_from_key", ("bit type %s", to->c_ptr_quick())); - key_length-= length; + DBUG_PRINT("ha_federated::create_where_from_key", + ("bit type %s", to->c_ptr_quick())); + key_length -= length; continue; } if (key_part->key_part_flag & HA_BLOB_PART) { uint blob_length= uint2korr(key); - key+= HA_KEY_BLOB_LENGTH; - key_length-= HA_KEY_BLOB_LENGTH; + key += HA_KEY_BLOB_LENGTH; + key_length -= HA_KEY_BLOB_LENGTH; tmp.set_quick((char*) key, blob_length, &my_charset_bin); if (append_escaped(to, &tmp)) 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; } else if (key_part->key_part_flag & HA_VAR_LENGTH_PART) { length= uint2korr(key); - key+= HA_KEY_BLOB_LENGTH; + key += HA_KEY_BLOB_LENGTH; tmp.set_quick((char*) key, length, &my_charset_bin); if (append_escaped(to, &tmp)) 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 { - 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]; 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 (append_escaped(to, res)) 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())) DBUG_RETURN(1); } if (needs_quotes && to->append("'")) DBUG_RETURN(1); - DBUG_PRINT("ha_federated::create_where_from_key", ("final value for 'to' %s", to->c_ptr_quick())); - key+= length; - key_length-= length; + DBUG_PRINT("ha_federated::create_where_from_key", + ("final value for 'to' %s", to->c_ptr_quick())); + key += length; + key_length -= length; DBUG_RETURN(0); } 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 pass to each federated handler. Do you have to have one of these? Well, you @@ -742,13 +746,13 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) // share->table_name has the file location - we want the actual table's // name! - table_base_name= (char *)table->s->table_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. - 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 - best method. + 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 + do this. Since you will not want to do this, this is probably the next + best method. */ if (!federated_init) { @@ -757,9 +761,9 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) 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); + 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); } @@ -767,41 +771,43 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table) table_name_length= (uint) strlen(table_name); table_base_name_length= (uint) strlen(table_base_name); - if (!(share= (FEDERATED_SHARE*) hash_search(&federated_open_tables, - (byte*) table_name, - table_name_length))) + if (!(share= (FEDERATED_SHARE *) hash_search(&federated_open_tables, + (byte *) table_name, + table_name_length))) { query.set_charset(system_charset_info); query.append("SELECT * FROM "); query.append(table_base_name); - + if (!(share= (FEDERATED_SHARE *) my_multi_malloc(MYF(MY_WME | MY_ZEROFILL), &share, sizeof(*share), - &tmp_table_name, table_name_length+1, - &tmp_table_base_name, table_base_name_length+1, - &select_query, query.length()+1, - NullS))) + &tmp_table_name, table_name_length + 1, + &tmp_table_base_name, table_base_name_length + 1, + &select_query, query.length() + 1, NullS))) { pthread_mutex_unlock(&federated_mutex); return NULL; } - load_conn_info(share, table); + if (parse_url(share, table, 0)) + goto error; + share->use_count= 0; share->table_name_length= table_name_length; share->table_name= tmp_table_name; share->table_base_name_length= table_base_name_length; share->table_base_name= tmp_table_base_name; share->select_query= select_query; - strmov(share->table_name,table_name); - strmov(share->table_base_name,table_base_name); - strmov(share->select_query,query.c_ptr_quick()); - DBUG_PRINT("ha_federated::get_share",("share->select_query %s", share->select_query)); - if (my_hash_insert(&federated_open_tables, (byte*) share)) + strmov(share->table_name, table_name); + strmov(share->table_base_name, table_base_name); + strmov(share->select_query, query.ptr()); + DBUG_PRINT("ha_federated::get_share", + ("share->select_query %s", share->select_query)); + if (my_hash_insert(&federated_open_tables, (byte *) share)) goto error; 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++; pthread_mutex_unlock(&federated_mutex); @@ -813,6 +819,9 @@ error2: pthread_mutex_destroy(&share->mutex); error: pthread_mutex_unlock(&federated_mutex); + hash_delete(&federated_open_tables, (byte *) share); + if (share->scheme) + my_free((gptr) share->scheme, MYF(0)); my_free((gptr) share, MYF(0)); return NULL; @@ -827,9 +836,14 @@ error: static int free_share(FEDERATED_SHARE *share) { pthread_mutex_lock(&federated_mutex); + + if (share->scheme) + my_free((gptr) share->scheme, MYF(0)); + if (!--share->use_count) { - hash_delete(&federated_open_tables, (byte*) share); + hash_delete(&federated_open_tables, (byte *) share); + hash_free(&federated_open_tables); thr_lock_delete(&share->lock); pthread_mutex_destroy(&share->mutex); my_free((gptr) share, MYF(0)); @@ -847,7 +861,13 @@ static int free_share(FEDERATED_SHARE *share) in handler.cc. */ const char **ha_federated::bas_ext() const -{ static const char *ext[]= { NullS }; return ext; } +{ + static const char *ext[]= + { + NullS + }; + return ext; +} /* @@ -867,23 +887,20 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) if (!(share= get_share(name, table))) 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() */ - mysql= mysql_init(0); - DBUG_PRINT("ha_federated::open",("hostname %s", share->hostname)); - DBUG_PRINT("ha_federated::open",("username %s", share->username)); - DBUG_PRINT("ha_federated::open",("password %s", share->password)); - DBUG_PRINT("ha_federated::open",("database %s", share->database)); - DBUG_PRINT("ha_federated::open",("port %d", share->port)); + mysql= mysql_init(0); + DBUG_PRINT("ha_federated::open", ("hostname %s", share->hostname)); + DBUG_PRINT("ha_federated::open", ("username %s", share->username)); + DBUG_PRINT("ha_federated::open", ("password %s", share->password)); + DBUG_PRINT("ha_federated::open", ("database %s", share->database)); + DBUG_PRINT("ha_federated::open", ("port %d", share->port)); if (!mysql_real_connect(mysql, - share->hostname, - share->username, - share->password, - share->database, - share->port, - NULL, - 0)) + share->hostname, + share->username, + share->password, + share->database, share->port, NULL, 0)) { my_error(ER_CONNECT_TO_MASTER, MYF(0), mysql_error(mysql)); DBUG_RETURN(ER_CONNECT_TO_MASTER); @@ -905,6 +922,15 @@ int ha_federated::open(const char *name, int mode, uint test_if_locked) int ha_federated::close(void) { 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 */ mysql_close(mysql); DBUG_RETURN(free_share(share)); @@ -929,10 +955,12 @@ int ha_federated::close(void) 1 if NULL 0 otherwise */ -inline uint field_in_record_is_null ( - TABLE* table, /* in: MySQL table object */ - Field* field, /* in: MySQL field object */ - char* record) /* in: a row in MySQL format */ +inline uint field_in_record_is_null(TABLE * table, /* in: MySQL table + object */ + Field * field, /* in: MySQL field + object */ + char *record) /* in: a row in MySQL + format */ { int null_offset; DBUG_ENTER("ha_federated::field_in_record_is_null"); @@ -963,11 +991,11 @@ inline uint field_in_record_is_null ( */ int ha_federated::write_row(byte * buf) { - int x= 0, num_fields= 0; + uint x= 0, num_fields= 0; Field **field; ulong current_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 values_buffer[IO_SIZE], insert_field_value_buffer[IO_SIZE]; @@ -980,40 +1008,41 @@ int ha_federated::write_row(byte * buf) values_string.length(0); // The actual value of the field, to be added to the values_string 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); DBUG_ENTER("ha_federated::write_row"); /* - I want to use this and the next line, but the repository needs to be - updated to do so + I want to use this and the next line, but the repository needs to be + updated to do so */ - statistic_increment(table->in_use->status_var.ha_write_count,&LOCK_status); + statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status); if (table->timestamp_field_type & TIMESTAMP_AUTO_SET_ON_INSERT) table->timestamp_field->set_time(); /* - 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 - this query id + 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 + this query id */ current_query_id= table->in_use->query_id; DBUG_PRINT("ha_federated::write_row", ("current query id %d", current_query_id)); // start off our string - insert_string.append("INSERT INTO "); + insert_string.append("INSERT INTO "); insert_string.append(share->table_base_name); // start both our field and field values strings insert_string.append(" ("); values_string.append(" VALUES ("); /* - 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 - such as in the case of INSERT INTO table VALUES (val1, val2, valN) + 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 + 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) all_fields_have_same_query_id= 0; @@ -1021,18 +1050,18 @@ int ha_federated::write_row(byte * buf) tmp_query_id= (*field)->query_id; } /* - loop through the field pointer array, add any fields to both the values - list and the fields list that match the current query id + loop through the field pointer array, add any fields to both the values + 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())); // 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 ) - || all_fields_have_same_query_id) + if (((*field)->query_id && (*field)->query_id == current_query_id) + || all_fields_have_same_query_id) { num_fields++; - + if ((*field)->is_null()) { DBUG_PRINT("ha_federated::write_row", @@ -1060,30 +1089,28 @@ int ha_federated::write_row(byte * buf) // append commas between both fields and fieldnames insert_string.append(','); values_string.append(','); - DBUG_PRINT("ha_federated::write_row", - ("insert_string %s values_string %s insert_field_value_string %s", - insert_string.c_ptr_quick(), values_string.c_ptr_quick(), - insert_field_value_string.c_ptr_quick())); + DBUG_PRINT("ha_federated::write_row", + ("insert_string %s values_string %s insert_field_value_string %s", + insert_string.c_ptr_quick(), values_string.c_ptr_quick(), + insert_field_value_string.c_ptr_quick())); } } /* - chop of the trailing comma, or if there were no fields, a '(' - So, "INSERT INTO foo (" becomes "INSERT INTO foo " - or, with fields, "INSERT INTO foo (field1, field2," becomes + chop of the trailing comma, or if there were no fields, a '(' + So, "INSERT INTO foo (" becomes "INSERT INTO foo " + or, with fields, "INSERT INTO foo (field1, field2," becomes "INSERT INTO foo (field1, field2" */ insert_string.chop(); - /* - 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 '(' - insert will be "INSERT INTO t1 VALUES ();" + 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 '(' + insert will be "INSERT INTO t1 VALUES ();" */ - DBUG_PRINT("ha_federated::write_row",("x %d num fields %d", - x, num_fields)); + DBUG_PRINT("ha_federated::write_row", ("x %d num fields %d", x, num_fields)); if (num_fields > 0) { // chops off leading commas @@ -1092,18 +1119,17 @@ int ha_federated::write_row(byte * buf) } // we always want to append this, even if there aren't any fields values_string.append(')'); - + // add the values insert_string.append(values_string); - DBUG_PRINT("ha_federated::write_row",("insert query %s", - insert_string.c_ptr_quick())); + DBUG_PRINT("ha_federated::write_row", ("insert query %s", + insert_string.c_ptr_quick())); - if (mysql_real_query(mysql, insert_string.c_ptr_quick(), - insert_string.length())) + if (mysql_real_query(mysql, insert_string.ptr(), insert_string.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(0); @@ -1125,22 +1151,21 @@ int ha_federated::write_row(byte * buf) Called from sql_select.cc, sql_acl.cc, sql_update.cc, and sql_insert.cc. */ -int ha_federated::update_row( - const byte * old_data, - byte * new_data - ) +int ha_federated::update_row(const byte * old_data, byte * new_data) { - int x= 0; + uint x= 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 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); + String old_field_value(old_field_value_buffer, sizeof(old_field_value_buffer), + &my_charset_bin); old_field_value.length(0); // 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); // stores the update query String update_string(update_buffer, sizeof(update_buffer), &my_charset_bin); @@ -1153,10 +1178,10 @@ int ha_federated::update_row( has_a_primary_key= table->s->primary_key == 0 ? 1 : 0; - primary_key_field_num= has_a_primary_key ? - table->key_info[table->s->primary_key].key_part->fieldnr -1 : -1; + primary_key_field_num= has_a_primary_key ? + table->key_info[table->s->primary_key].key_part->fieldnr - 1 : -1; 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(share->table_base_name); @@ -1171,19 +1196,19 @@ int ha_federated::update_row( used to create SET field=value and old data is used to create WHERE 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 - 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 - 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 + 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 + 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 + 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); } else @@ -1200,61 +1225,59 @@ int ha_federated::update_row( (*field)->val_str(&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) where_string.append("="); } - else - if (! field_in_record_is_null(table, *field, (char*) old_data)) - where_string.append("="); + else if (!field_in_record_is_null(table, *field, (char*) old_data)) + where_string.append("="); } - if ( has_a_primary_key) + if (has_a_primary_key) { if (x == primary_key_field_num) { (*field)->val_str(&old_field_value, - (char *)(old_data + (*field)->offset())); + (char*) (old_data + (*field)->offset())); (*field)->quote_data(&old_field_value); where_string.append(old_field_value); } } else { - if (field_in_record_is_null(table, *field, (char*) old_data)) - where_string.append(" IS NULL "); - else - { - (*field)->val_str(&old_field_value, - (char *)(old_data + (*field)->offset())); - (*field)->quote_data(&old_field_value); - where_string.append(old_field_value); - } + if (field_in_record_is_null(table, *field, (char*) old_data)) + where_string.append(" IS NULL "); + else + { + (*field)->val_str(&old_field_value, + (char*) (old_data + (*field)->offset())); + (*field)->quote_data(&old_field_value); + where_string.append(old_field_value); + } } update_string.append(new_field_value); new_field_value.length(0); - if ((uint) x+1 < table->s->fields) + if (x + 1 < table->s->fields) { update_string.append(", "); - if (! has_a_primary_key) + if (!has_a_primary_key) where_string.append(" AND "); } old_field_value.length(0); } update_string.append(" WHERE "); - update_string.append(where_string.c_ptr_quick()); - if (! has_a_primary_key) + update_string.append(where_string.ptr()); + if (!has_a_primary_key) update_string.append(" LIMIT 1"); DBUG_PRINT("ha_federated::update_row", ("Final update query: %s", update_string.c_ptr_quick())); - if (mysql_real_query(mysql, update_string.c_ptr_quick(), - update_string.length())) + if (mysql_real_query(mysql, update_string.ptr(), update_string.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); } @@ -1277,7 +1300,7 @@ int ha_federated::update_row( */ int ha_federated::delete_row(const byte * buf) { - int x= 0; + uint x= 0; char delete_buffer[IO_SIZE]; char data_buffer[IO_SIZE]; @@ -1292,7 +1315,7 @@ int ha_federated::delete_row(const byte * buf) delete_string.append(share->table_base_name); 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); @@ -1307,22 +1330,21 @@ int ha_federated::delete_row(const byte * buf) (*field)->val_str(&data_string); (*field)->quote_data(&data_string); } - + delete_string.append(data_string); data_string.length(0); - if ((uint) x+1 < table->s->fields) + if (x + 1 < table->s->fields) delete_string.append(" AND "); } delete_string.append(" LIMIT 1"); DBUG_PRINT("ha_federated::delete_row", ("Delete sql: %s", delete_string.c_ptr_quick())); - if ( mysql_real_query(mysql, delete_string.c_ptr_quick(), - delete_string.length())) + if (mysql_real_query(mysql, delete_string.ptr(), delete_string.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(0); @@ -1336,9 +1358,9 @@ int ha_federated::delete_row(const byte * buf) a WHERE clause on a non-primary key index, simply calls index_read_idx. */ int ha_federated::index_read(byte * buf, const byte * key, - uint key_len __attribute__((unused)), - enum ha_rkey_function find_flag - __attribute__((unused))) + uint key_len __attribute__ ((unused)), + enum ha_rkey_function find_flag + __attribute__ ((unused))) { DBUG_ENTER("ha_federated::index_read"); DBUG_RETURN(index_read_idx(buf, active_index, key, key_len, find_flag)); @@ -1354,9 +1376,9 @@ int ha_federated::index_read(byte * buf, const byte * key, uses a PRIMARY KEY index. */ int ha_federated::index_read_idx(byte * buf, uint index, const byte * key, - uint key_len __attribute__((unused)), - enum ha_rkey_function find_flag - __attribute__((unused))) + uint key_len __attribute__ ((unused)), + enum ha_rkey_function find_flag + __attribute__ ((unused))) { char index_value[IO_SIZE]; char key_value[IO_SIZE]; @@ -1370,27 +1392,34 @@ int ha_federated::index_read_idx(byte * buf, uint index, const byte * key, sql_query.length(0); 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(" WHERE "); - keylen= strlen((char *)(key)); + keylen= strlen((char*) (key)); create_where_from_key(&index_string, &table->key_info[index], key, keylen); sql_query.append(index_string); 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(), - index_string.length())); + ("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("ha_federated::index_read_idx", - ("current position %d sql_query %s", current_position, - sql_query.c_ptr_quick())); + ("current position %d sql_query %s", current_position, + sql_query.c_ptr_quick())); - if (mysql_real_query(mysql, sql_query.c_ptr_quick(), sql_query.length())) + if (result) { - my_error(ER_QUERY_ON_MASTER,MYF(0),mysql_error(mysql)); - DBUG_RETURN(ER_QUERY_ON_MASTER); + 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)); + DBUG_RETURN(ER_QUERY_ON_MASTER); } result= mysql_store_result(mysql); @@ -1403,7 +1432,7 @@ int ha_federated::index_read_idx(byte * buf, uint index, const byte * key, if (mysql_errno(mysql)) { table->status= STATUS_NOT_FOUND; - DBUG_RETURN(mysql_errno(mysql)); + DBUG_RETURN(mysql_errno(mysql)); } DBUG_RETURN(rnd_next(buf)); @@ -1449,23 +1478,54 @@ int ha_federated::rnd_init(bool scan) DBUG_ENTER("ha_federated::rnd_init"); int num_fields, rows; - DBUG_PRINT("ha_federated::rnd_init", - ("share->select_query %s", share->select_query)); - if (mysql_real_query(mysql, share->select_query, strlen(share->select_query))) + /* + This 'scan' flag is incredibly important for this handler to work properly, + 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_RETURN(ER_QUERY_ON_MASTER); - } - result= mysql_store_result(mysql); + DBUG_PRINT("ha_federated::rnd_init", + ("share->select_query %s", share->select_query)); + if (result) + { + DBUG_PRINT("ha_federated::rnd_init", + ("mysql_free_result address %lx", result)); + mysql_free_result(result); + result= 0; + } - if (mysql_errno(mysql)) - DBUG_RETURN(mysql_errno(mysql)); + if (mysql_real_query + (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); } int 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); DBUG_RETURN(index_end()); } @@ -1493,10 +1553,12 @@ int ha_federated::rnd_next(byte *buf) // Fetch a row, insert it back in a row format. 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(convert_row_to_internal_format(buf,row)); + + DBUG_RETURN(convert_row_to_internal_format(buf, row)); } @@ -1517,7 +1579,7 @@ void ha_federated::position(const byte *record) { DBUG_ENTER("ha_federated::position"); //ha_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; } @@ -1535,11 +1597,24 @@ void ha_federated::position(const byte *record) int ha_federated::rnd_pos(byte * buf, byte *pos) { 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)); // pos is not aligned - result->current_row= 0; - result->data_cursor= current_position; - DBUG_RETURN(rnd_next(buf)); + /* + we do not need to do any of this if there has been a scan performed already, or + if this is an update and index_read_idx already has a result set in which to build + it's update query from + */ + if (scan_flag) + { + statistic_increment(table->in_use->status_var.ha_read_rnd_count, + &LOCK_status); + memcpy_fixed(¤t_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); } @@ -1590,7 +1665,7 @@ int ha_federated::rnd_pos(byte * buf, byte *pos) void ha_federated::info(uint flag) { DBUG_ENTER("ha_federated::info"); - records= 10000; // Fake! + records= 10000; // Fake! DBUG_VOID_RETURN; } @@ -1618,9 +1693,10 @@ int ha_federated::delete_all_rows() query.append("TRUNCATE "); query.append(share->table_base_name); - if (mysql_real_query(mysql, query.c_ptr_quick(), query.length())) { - my_error(ER_QUERY_ON_MASTER,MYF(0),mysql_error(mysql)); - DBUG_RETURN(ER_QUERY_ON_MASTER); + 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); } DBUG_RETURN(HA_ERR_WRONG_COMMAND); @@ -1657,32 +1733,31 @@ int ha_federated::delete_all_rows() Called from lock.cc by get_lock_data(). */ THR_LOCK_DATA **ha_federated::store_lock(THD *thd, - THR_LOCK_DATA **to, - enum thr_lock_type lock_type) + THR_LOCK_DATA **to, + 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. - If TL_UNLOCK is set - If we are not doing a LOCK TABLE or DISCARD/IMPORT - TABLESPACE, then allow multiple writers + Here is where we get into the guts of a row level lock. + If TL_UNLOCK is set + If we are not doing a LOCK TABLE or DISCARD/IMPORT + TABLESPACE, then allow multiple writers */ if ((lock_type >= TL_WRITE_CONCURRENT_INSERT && - lock_type <= TL_WRITE) && !thd->in_lock_tables - && !thd->tablespace_op) + lock_type <= TL_WRITE) && !thd->in_lock_tables && !thd->tablespace_op) lock_type= TL_WRITE_ALLOW_WRITE; /* - In queries of type INSERT INTO t1 SELECT ... FROM t2 ... - MySQL would use the lock TL_READ_NO_INSERT on t2, and that - would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts - to t2. Convert the lock to a normal read lock to allow - concurrent inserts to t2. + In queries of type INSERT INTO t1 SELECT ... FROM t2 ... + MySQL would use the lock TL_READ_NO_INSERT on t2, and that + would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts + to t2. Convert the lock to a normal read lock to allow + 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= lock_type; @@ -1699,19 +1774,16 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd, create tables if they do not exist. */ 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; DBUG_ENTER("ha_federated::create"); - retcode= parse_url(&tmp, table_arg, 1); - if (retcode < 0) + if (parse_url(&tmp, table_arg, 1)) { - DBUG_PRINT("ha_federated::create", - ("ERROR: on table creation for %s called parse_url, retcode %d", - create_info->data_file_name, retcode)); + my_error(ER_CANT_CREATE_TABLE, MYF(0)); DBUG_RETURN(ER_CANT_CREATE_TABLE); } + my_free((gptr) tmp.scheme, MYF(0)); DBUG_RETURN(0); } -#endif /* HAVE_FEDERATED_DB */ +#endif /* HAVE_FEDERATED_DB */ diff --git a/sql/ha_federated.h b/sql/ha_federated.h index 56f5e6de4b7..6870a0902e8 100755 --- a/sql/ha_federated.h +++ b/sql/ha_federated.h @@ -62,6 +62,7 @@ class ha_federated: public handler FEDERATED_SHARE *share; /* Shared lock info */ MYSQL *mysql; MYSQL_RES *result; + bool scan_flag; uint ref_length; uint fetch_num; // stores the fetch num MYSQL_ROW_OFFSET current_position; // Current position used by ::position() @@ -76,7 +77,7 @@ private: public: ha_federated(TABLE *table): handler(table), - mysql(0), + mysql(0), result(0), scan_flag(0), ref_length(sizeof(MYSQL_ROW_OFFSET)), current_position(0) { } |