|
|
|
@@ -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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -376,6 +379,7 @@ static byte* federated_get_key(FEDERATED_SHARE *share,uint *length,
|
|
|
|
|
parse_url()
|
|
|
|
|
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,23 +405,24 @@ 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",
|
|
|
|
@@ -425,9 +430,9 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, uint table_create_fla
|
|
|
|
|
to a MySQL database!!!\n"));
|
|
|
|
|
my_error(error_num, MYF(0),
|
|
|
|
|
"ERROR: federated handler only supports remote 'mysql://' database");
|
|
|
|
|
DBUG_RETURN(-1);
|
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
}
|
|
|
|
|
share->username+= 3;
|
|
|
|
|
share->username += 3;
|
|
|
|
|
|
|
|
|
|
if ((share->hostname= strchr(share->username, '@')))
|
|
|
|
|
{
|
|
|
|
@@ -446,12 +451,12 @@ static int parse_url(FEDERATED_SHARE *share, TABLE *table, uint table_create_fla
|
|
|
|
|
("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);
|
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
}
|
|
|
|
|
/*
|
|
|
|
|
Found that if the string is:
|
|
|
|
|
user:@hostname:port/database/table
|
|
|
|
|
Then password is a null string, so set to NULL
|
|
|
|
|
user:@hostname:port/database/table
|
|
|
|
|
Then password is a null string, so set to NULL
|
|
|
|
|
*/
|
|
|
|
|
if ((share->password[0] == '\0'))
|
|
|
|
|
share->password= NULL;
|
|
|
|
@@ -466,7 +471,7 @@ Then password is a null string, so set to NULL
|
|
|
|
|
("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);
|
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ((share->database= strchr(share->hostname, '/')))
|
|
|
|
@@ -495,7 +500,7 @@ Then password is a null string, so set to NULL
|
|
|
|
|
("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);
|
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@@ -504,7 +509,7 @@ Then password is a null string, so set to NULL
|
|
|
|
|
("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);
|
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
}
|
|
|
|
|
// make sure there's not an extra /
|
|
|
|
|
if ((strchr(share->table_base_name, '/')))
|
|
|
|
@@ -513,16 +518,22 @@ Then password is a null string, so set to NULL
|
|
|
|
|
("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);
|
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
}
|
|
|
|
|
if (share->hostname[0] == '\0')
|
|
|
|
|
share->hostname= NULL;
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
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
|
|
|
|
|
{
|
|
|
|
@@ -530,7 +541,7 @@ Then password is a null string, so set to NULL
|
|
|
|
|
("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);
|
|
|
|
|
DBUG_RETURN(1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
@@ -539,7 +550,7 @@ Then password is a null string, so set to NULL
|
|
|
|
|
("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);
|
|
|
|
|
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
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
|
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])
|
|
|
|
|
{
|
|
|
|
|
(*field)->set_null();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
/*
|
|
|
|
|
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))
|
|
|
|
|
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()));
|
|
|
|
|
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;
|
|
|
|
|
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,8 +746,8 @@ 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
|
|
|
|
@@ -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,8 +771,8 @@ 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,
|
|
|
|
|
if (!(share= (FEDERATED_SHARE *) hash_search(&federated_open_tables,
|
|
|
|
|
(byte *) table_name,
|
|
|
|
|
table_name_length)))
|
|
|
|
|
{
|
|
|
|
|
query.set_charset(system_charset_info);
|
|
|
|
@@ -778,30 +782,32 @@ static FEDERATED_SHARE *get_share(const char *table_name, TABLE *table)
|
|
|
|
|
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));
|
|
|
|
|
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->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,7 +1008,8 @@ 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");
|
|
|
|
@@ -988,7 +1017,7 @@ int ha_federated::write_row(byte * buf)
|
|
|
|
|
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();
|
|
|
|
|
|
|
|
|
@@ -1013,7 +1042,7 @@ int ha_federated::write_row(byte * buf)
|
|
|
|
|
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;
|
|
|
|
@@ -1024,11 +1053,11 @@ int ha_federated::write_row(byte * buf)
|
|
|
|
|
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 )
|
|
|
|
|
if (((*field)->query_id && (*field)->query_id == current_query_id)
|
|
|
|
|
|| all_fields_have_same_query_id)
|
|
|
|
|
{
|
|
|
|
|
num_fields++;
|
|
|
|
@@ -1076,14 +1105,12 @@ int ha_federated::write_row(byte * buf)
|
|
|
|
|
*/
|
|
|
|
|
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 ();"
|
|
|
|
|
*/
|
|
|
|
|
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
|
|
|
|
@@ -1096,13 +1123,12 @@ int ha_federated::write_row(byte * buf)
|
|
|
|
|
// add the values
|
|
|
|
|
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()));
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
|
|
|
|
|
DBUG_RETURN(ER_QUERY_ON_MASTER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -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);
|
|
|
|
@@ -1154,7 +1179,7 @@ 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;
|
|
|
|
|
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"));
|
|
|
|
|
|
|
|
|
@@ -1172,7 +1197,7 @@ int ha_federated::update_row(
|
|
|
|
|
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
|
|
|
|
@@ -1200,22 +1225,21 @@ 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))
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
@@ -1227,7 +1251,7 @@ int ha_federated::update_row(
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
(*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);
|
|
|
|
|
}
|
|
|
|
@@ -1235,25 +1259,24 @@ int ha_federated::update_row(
|
|
|
|
|
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));
|
|
|
|
|
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);
|
|
|
|
|
|
|
|
|
@@ -1311,17 +1334,16 @@ int ha_federated::delete_row(const byte * buf)
|
|
|
|
|
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));
|
|
|
|
|
my_error(ER_QUERY_ON_MASTER, MYF(0), mysql_error(mysql));
|
|
|
|
|
DBUG_RETURN(ER_QUERY_ON_MASTER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -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)),
|
|
|
|
|
uint key_len __attribute__ ((unused)),
|
|
|
|
|
enum ha_rkey_function find_flag
|
|
|
|
|
__attribute__((unused)))
|
|
|
|
|
__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)),
|
|
|
|
|
uint key_len __attribute__ ((unused)),
|
|
|
|
|
enum ha_rkey_function find_flag
|
|
|
|
|
__attribute__((unused)))
|
|
|
|
|
__attribute__ ((unused)))
|
|
|
|
|
{
|
|
|
|
|
char index_value[IO_SIZE];
|
|
|
|
|
char key_value[IO_SIZE];
|
|
|
|
@@ -1370,26 +1392,33 @@ 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(),
|
|
|
|
|
("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()));
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
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);
|
|
|
|
@@ -1449,23 +1478,54 @@ int ha_federated::rnd_init(bool scan)
|
|
|
|
|
DBUG_ENTER("ha_federated::rnd_init");
|
|
|
|
|
int num_fields, rows;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
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)
|
|
|
|
|
{
|
|
|
|
|
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)))
|
|
|
|
|
if (result)
|
|
|
|
|
{
|
|
|
|
|
my_error(ER_QUERY_ON_MASTER,MYF(0),mysql_error(mysql));
|
|
|
|
|
DBUG_PRINT("ha_federated::rnd_init",
|
|
|
|
|
("mysql_free_result address %lx", result));
|
|
|
|
|
mysql_free_result(result);
|
|
|
|
|
result= 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
|
/*
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1618,8 +1693,9 @@ 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));
|
|
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -1670,8 +1746,7 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@@ -1701,17 +1776,14 @@ THR_LOCK_DATA **ha_federated::store_lock(THD *thd,
|
|
|
|
|
int ha_federated::create(const char *name, TABLE *table_arg,
|
|
|
|
|
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 */
|
|
|
|
|