848 lines
22 KiB
C++
848 lines
22 KiB
C++
/* Copyright (c) 2010, 2019, Oracle and/or its affiliates. All rights reserved.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; version 2 of the License.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
|
|
#include "rpl_info_table.h"
|
|
|
|
#include "dynamic_ids.h" // Server_ids
|
|
#include "log.h" // sql_print_error
|
|
#include "rpl_info_table_access.h" // Rpl_info_table_access
|
|
#include "rpl_info_values.h" // Rpl_info_values
|
|
#include "sql_class.h" // THD
|
|
|
|
|
|
Rpl_info_table::Rpl_info_table(uint nparam,
|
|
const char* param_schema,
|
|
const char *param_table,
|
|
const uint param_n_pk_fields,
|
|
const uint *param_pk_field_indexes)
|
|
:Rpl_info_handler(nparam), is_transactional(FALSE)
|
|
{
|
|
str_schema.str= str_table.str= NULL;
|
|
str_schema.length= str_table.length= 0;
|
|
|
|
size_t schema_length= strlen(param_schema);
|
|
if ((str_schema.str= (char *) my_malloc(key_memory_Rpl_info_table,
|
|
schema_length + 1, MYF(0))))
|
|
{
|
|
str_schema.length= schema_length;
|
|
strmake(str_schema.str, param_schema, schema_length);
|
|
}
|
|
|
|
size_t table_length= strlen(param_table);
|
|
if ((str_table.str= (char *) my_malloc(key_memory_Rpl_info_table,
|
|
table_length + 1, MYF(0))))
|
|
{
|
|
str_table.length= table_length;
|
|
strmake(str_table.str, param_table, table_length);
|
|
}
|
|
|
|
if ((description= (char *)
|
|
my_malloc(key_memory_Rpl_info_table,
|
|
str_schema.length + str_table.length + 2, MYF(0))))
|
|
{
|
|
char *pos= my_stpcpy(description, param_schema);
|
|
pos= my_stpcpy(pos, ".");
|
|
pos= my_stpcpy(pos, param_table);
|
|
}
|
|
|
|
m_n_pk_fields= param_n_pk_fields;
|
|
m_pk_field_indexes= param_pk_field_indexes;
|
|
|
|
access= new Rpl_info_table_access();
|
|
}
|
|
|
|
Rpl_info_table::~Rpl_info_table()
|
|
{
|
|
delete access;
|
|
|
|
my_free(description);
|
|
|
|
my_free(str_table.str);
|
|
|
|
my_free(str_schema.str);
|
|
}
|
|
|
|
int Rpl_info_table::do_init_info()
|
|
{
|
|
return do_init_info(FIND_KEY, 0);
|
|
}
|
|
|
|
int Rpl_info_table::do_init_info(uint instance)
|
|
{
|
|
return do_init_info(FIND_KEY, instance);
|
|
}
|
|
|
|
int Rpl_info_table::do_init_info(enum_find_method method, uint instance)
|
|
{
|
|
int error= 1;
|
|
enum enum_return_id res= FOUND_ID;
|
|
TABLE *table= NULL;
|
|
sql_mode_t saved_mode;
|
|
Open_tables_backup backup;
|
|
|
|
DBUG_ENTER("Rlp_info_table::do_init_info");
|
|
|
|
THD *thd= access->create_thd();
|
|
|
|
saved_mode= thd->variables.sql_mode;
|
|
tmp_disable_binlog(thd);
|
|
|
|
/*
|
|
Opens and locks the rpl_info table before accessing it.
|
|
*/
|
|
if (access->open_table(thd, str_schema, str_table,
|
|
get_number_info(), TL_WRITE,
|
|
&table, &backup))
|
|
goto end;
|
|
|
|
if (verify_table_primary_key_fields(table))
|
|
goto end;
|
|
|
|
/*
|
|
Points the cursor at the row to be read according to the
|
|
keys.
|
|
*/
|
|
switch (method)
|
|
{
|
|
case FIND_KEY:
|
|
res= access->find_info(field_values, table);
|
|
break;
|
|
|
|
case FIND_SCAN:
|
|
res= access->scan_info(table, instance);
|
|
break;
|
|
|
|
default:
|
|
DBUG_ASSERT(0);
|
|
break;
|
|
}
|
|
|
|
if (res == FOUND_ID)
|
|
{
|
|
/*
|
|
Reads the information stored in the rpl_info table into a
|
|
set of variables. If there is a failure, an error is returned.
|
|
*/
|
|
if (access->load_info_values(get_number_info(), table->field,
|
|
field_values))
|
|
goto end;
|
|
}
|
|
error= (res == ERROR_ID);
|
|
end:
|
|
/*
|
|
Unlocks and closes the rpl_info table.
|
|
*/
|
|
error= access->close_table(thd, table, &backup, error) || error;
|
|
reenable_binlog(thd);
|
|
thd->variables.sql_mode= saved_mode;
|
|
access->drop_thd(thd);
|
|
DBUG_RETURN(error);
|
|
}
|
|
|
|
int Rpl_info_table::do_flush_info(const bool force)
|
|
{
|
|
int error= 1;
|
|
enum enum_return_id res= FOUND_ID;
|
|
TABLE *table= NULL;
|
|
sql_mode_t saved_mode;
|
|
Open_tables_backup backup;
|
|
|
|
DBUG_ENTER("Rpl_info_table::do_flush_info");
|
|
|
|
if (!(force || (sync_period &&
|
|
++(sync_counter) >= sync_period)))
|
|
DBUG_RETURN(0);
|
|
|
|
THD *thd= access->create_thd();
|
|
|
|
sync_counter= 0;
|
|
saved_mode= thd->variables.sql_mode;
|
|
tmp_disable_binlog(thd);
|
|
thd->is_operating_substatement_implicitly= true;
|
|
|
|
/*
|
|
Opens and locks the rpl_info table before accessing it.
|
|
*/
|
|
if (access->open_table(thd, str_schema, str_table,
|
|
get_number_info(), TL_WRITE,
|
|
&table, &backup))
|
|
goto end;
|
|
|
|
/*
|
|
Points the cursor at the row to be read according to the
|
|
keys. If the row is not found an error is reported.
|
|
*/
|
|
if ((res= access->find_info(field_values, table)) == NOT_FOUND_ID)
|
|
{
|
|
/*
|
|
Prepares the information to be stored before calling ha_write_row.
|
|
*/
|
|
empty_record(table);
|
|
if (access->store_info_values(get_number_info(), table->field,
|
|
field_values))
|
|
goto end;
|
|
|
|
/*
|
|
Inserts a new row into rpl_info table.
|
|
*/
|
|
if ((error= table->file->ha_write_row(table->record[0])))
|
|
{
|
|
table->file->print_error(error, MYF(0));
|
|
/*
|
|
This makes sure that the error is 1 and not the status returned
|
|
by the handler.
|
|
*/
|
|
error= 1;
|
|
goto end;
|
|
}
|
|
error= 0;
|
|
}
|
|
else if (res == FOUND_ID)
|
|
{
|
|
/*
|
|
Prepares the information to be stored before calling ha_update_row.
|
|
*/
|
|
store_record(table, record[1]);
|
|
if (access->store_info_values(get_number_info(), table->field,
|
|
field_values))
|
|
goto end;
|
|
|
|
/*
|
|
Updates a row in the rpl_info table.
|
|
*/
|
|
if ((error= table->file->ha_update_row(table->record[1], table->record[0])) &&
|
|
error != HA_ERR_RECORD_IS_THE_SAME)
|
|
{
|
|
table->file->print_error(error, MYF(0));
|
|
/*
|
|
This makes sure that the error is 1 and not the status returned
|
|
by the handler.
|
|
*/
|
|
error= 1;
|
|
goto end;
|
|
}
|
|
error= 0;
|
|
}
|
|
|
|
end:
|
|
DBUG_EXECUTE_IF("mts_debug_concurrent_access",
|
|
{
|
|
while (thd->system_thread == SYSTEM_THREAD_SLAVE_WORKER &&
|
|
mts_debug_concurrent_access < 2 && mts_debug_concurrent_access > 0)
|
|
{
|
|
DBUG_PRINT("mts", ("Waiting while locks are acquired to show "
|
|
"concurrency in mts: %u %u\n",
|
|
mts_debug_concurrent_access,
|
|
thd->thread_id()));
|
|
my_sleep(6000000);
|
|
}
|
|
};
|
|
);
|
|
|
|
/*
|
|
Unlocks and closes the rpl_info table.
|
|
*/
|
|
error= access->close_table(thd, table, &backup, error) || error;
|
|
thd->is_operating_substatement_implicitly= false;
|
|
reenable_binlog(thd);
|
|
thd->variables.sql_mode= saved_mode;
|
|
access->drop_thd(thd);
|
|
DBUG_RETURN(error);
|
|
}
|
|
|
|
int Rpl_info_table::do_remove_info()
|
|
{
|
|
return do_clean_info();
|
|
}
|
|
|
|
int Rpl_info_table::do_clean_info()
|
|
{
|
|
int error= 1;
|
|
enum enum_return_id res= FOUND_ID;
|
|
TABLE *table= NULL;
|
|
sql_mode_t saved_mode;
|
|
Open_tables_backup backup;
|
|
|
|
DBUG_ENTER("Rpl_info_table::do_remove_info");
|
|
|
|
THD *thd= access->create_thd();
|
|
|
|
saved_mode= thd->variables.sql_mode;
|
|
tmp_disable_binlog(thd);
|
|
|
|
/*
|
|
Opens and locks the rpl_info table before accessing it.
|
|
*/
|
|
if (access->open_table(thd, str_schema, str_table,
|
|
get_number_info(), TL_WRITE,
|
|
&table, &backup))
|
|
goto end;
|
|
|
|
/*
|
|
Points the cursor at the row to be deleted according to the
|
|
keys. If the row is not found, the execution proceeds normally.
|
|
*/
|
|
if ((res= access->find_info(field_values, table)) == FOUND_ID)
|
|
{
|
|
/*
|
|
Deletes a row in the rpl_info table.
|
|
*/
|
|
if ((error= table->file->ha_delete_row(table->record[0])))
|
|
{
|
|
table->file->print_error(error, MYF(0));
|
|
goto end;
|
|
}
|
|
}
|
|
error= (res == ERROR_ID);
|
|
end:
|
|
/*
|
|
Unlocks and closes the rpl_info table.
|
|
*/
|
|
error= access->close_table(thd, table, &backup, error) || error;
|
|
reenable_binlog(thd);
|
|
thd->variables.sql_mode= saved_mode;
|
|
access->drop_thd(thd);
|
|
DBUG_RETURN(error);
|
|
}
|
|
|
|
/**
|
|
Removes records belonging to the channel_name parameter's channel.
|
|
|
|
@param nparam number of fields in the table
|
|
@param param_schema schema name
|
|
@param param_table table name
|
|
@param channel_name channel name
|
|
@param channel_field_idx channel name field index
|
|
|
|
@return 0 on success
|
|
1 when a failure happens
|
|
*/
|
|
int Rpl_info_table::do_reset_info(uint nparam,
|
|
const char* param_schema,
|
|
const char *param_table,
|
|
const char *channel_name,
|
|
uint channel_field_idx)
|
|
{
|
|
int error= 0;
|
|
TABLE *table= NULL;
|
|
sql_mode_t saved_mode;
|
|
Open_tables_backup backup;
|
|
Rpl_info_table *info= NULL;
|
|
THD *thd= NULL;
|
|
int handler_error= 0;
|
|
|
|
DBUG_ENTER("Rpl_info_table::do_reset_info");
|
|
|
|
if (!(info= new Rpl_info_table(nparam, param_schema,
|
|
param_table)))
|
|
DBUG_RETURN(1);
|
|
|
|
thd= info->access->create_thd();
|
|
saved_mode= thd->variables.sql_mode;
|
|
tmp_disable_binlog(thd);
|
|
|
|
/*
|
|
Opens and locks the rpl_info table before accessing it.
|
|
*/
|
|
if (info->access->open_table(thd, info->str_schema, info->str_table,
|
|
info->get_number_info(), TL_WRITE,
|
|
&table, &backup))
|
|
{
|
|
error= 1;
|
|
goto end;
|
|
}
|
|
|
|
if (!(handler_error= table->file->ha_index_init(0, 1)))
|
|
{
|
|
KEY *key_info= table->key_info;
|
|
|
|
/*
|
|
Currently this method is used only for Worker info table
|
|
resetting.
|
|
todo: for another table in future, consider to make use of the
|
|
passed parameter to locate the lookup key.
|
|
*/
|
|
DBUG_ASSERT(strcmp(info->str_table.str, "slave_worker_info") == 0);
|
|
|
|
if (info->verify_table_primary_key_fields(table))
|
|
{
|
|
error= 1;
|
|
table->file->ha_index_end();
|
|
goto end;
|
|
}
|
|
|
|
uint fieldnr= key_info->key_part[0].fieldnr - 1;
|
|
table->field[fieldnr]->store(channel_name,
|
|
strlen(channel_name),
|
|
&my_charset_bin);
|
|
uint key_len= key_info->key_part[0].store_length;
|
|
uchar *key_buf= table->field[fieldnr]->ptr;
|
|
|
|
if (!(handler_error= table->file->ha_index_read_map(table->record[0],
|
|
key_buf,
|
|
(key_part_map) 1,
|
|
HA_READ_KEY_EXACT)))
|
|
{
|
|
do
|
|
{
|
|
if ((handler_error= table->file->ha_delete_row(table->record[0])))
|
|
break;
|
|
}
|
|
while (!(handler_error= table->file->ha_index_next_same(table->record[0],
|
|
key_buf,
|
|
key_len)));
|
|
if (handler_error != HA_ERR_END_OF_FILE)
|
|
error= 1;
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
Being reset table can be even empty, and that's benign.
|
|
*/
|
|
if (handler_error != HA_ERR_KEY_NOT_FOUND)
|
|
error= 1;
|
|
}
|
|
|
|
if (error)
|
|
table->file->print_error(handler_error, MYF(0));
|
|
table->file->ha_index_end();
|
|
}
|
|
end:
|
|
/*
|
|
Unlocks and closes the rpl_info table.
|
|
*/
|
|
error= info->access->close_table(thd, table, &backup, error) || error;
|
|
reenable_binlog(thd);
|
|
thd->variables.sql_mode= saved_mode;
|
|
info->access->drop_thd(thd);
|
|
delete info;
|
|
DBUG_RETURN(error);
|
|
}
|
|
|
|
enum_return_check Rpl_info_table::do_check_info()
|
|
{
|
|
TABLE *table= NULL;
|
|
sql_mode_t saved_mode;
|
|
Open_tables_backup backup;
|
|
enum_return_check return_check= ERROR_CHECKING_REPOSITORY;
|
|
|
|
DBUG_ENTER("Rpl_info_table::do_check_info");
|
|
|
|
THD *thd= access->create_thd();
|
|
saved_mode= thd->variables.sql_mode;
|
|
|
|
/*
|
|
Opens and locks the rpl_info table before accessing it.
|
|
*/
|
|
if (access->open_table(thd, str_schema, str_table,
|
|
get_number_info(), TL_READ,
|
|
&table, &backup))
|
|
{
|
|
sql_print_warning("Info table is not ready to be used. Table "
|
|
"'%s.%s' cannot be opened.", str_schema.str,
|
|
str_table.str);
|
|
|
|
return_check= ERROR_CHECKING_REPOSITORY;
|
|
goto end;
|
|
}
|
|
|
|
/*
|
|
Points the cursor at the row to be read according to the
|
|
keys.
|
|
*/
|
|
if (access->find_info(field_values, table) != FOUND_ID)
|
|
{
|
|
/*
|
|
We cannot simply call my_error here because it does not
|
|
really means that there was a failure but only that the
|
|
record was not found.
|
|
*/
|
|
return_check= REPOSITORY_DOES_NOT_EXIST;
|
|
goto end;
|
|
}
|
|
return_check= REPOSITORY_EXISTS;
|
|
|
|
|
|
end:
|
|
/*
|
|
Unlocks and closes the rpl_info table.
|
|
*/
|
|
access->close_table(thd, table, &backup,
|
|
return_check == ERROR_CHECKING_REPOSITORY);
|
|
thd->variables.sql_mode= saved_mode;
|
|
access->drop_thd(thd);
|
|
DBUG_RETURN(return_check);
|
|
}
|
|
|
|
enum_return_check Rpl_info_table::do_check_info(uint instance)
|
|
{
|
|
TABLE *table= NULL;
|
|
sql_mode_t saved_mode;
|
|
Open_tables_backup backup;
|
|
enum_return_check return_check= ERROR_CHECKING_REPOSITORY;
|
|
|
|
DBUG_ENTER("Rpl_info_table::do_check_info");
|
|
|
|
THD *thd= access->create_thd();
|
|
saved_mode= thd->variables.sql_mode;
|
|
|
|
/*
|
|
Opens and locks the rpl_info table before accessing it.
|
|
*/
|
|
if (access->open_table(thd, str_schema, str_table,
|
|
get_number_info(), TL_READ,
|
|
&table, &backup))
|
|
{
|
|
sql_print_warning("Info table is not ready to be used. Table "
|
|
"'%s.%s' cannot be opened.", str_schema.str,
|
|
str_table.str);
|
|
|
|
return_check= ERROR_CHECKING_REPOSITORY;
|
|
goto end;
|
|
}
|
|
|
|
if (verify_table_primary_key_fields(table))
|
|
{
|
|
return_check= ERROR_CHECKING_REPOSITORY;
|
|
goto end;
|
|
}
|
|
|
|
/*
|
|
Points the cursor at the row to be read according to the
|
|
keys.
|
|
*/
|
|
if (access->scan_info(table, instance) != FOUND_ID)
|
|
{
|
|
/*
|
|
We cannot simply call my_error here because it does not
|
|
really means that there was a failure but only that the
|
|
record was not found.
|
|
*/
|
|
return_check= REPOSITORY_DOES_NOT_EXIST;
|
|
goto end;
|
|
}
|
|
return_check= REPOSITORY_EXISTS;
|
|
|
|
|
|
end:
|
|
/*
|
|
Unlocks and closes the rpl_info table.
|
|
*/
|
|
access->close_table(thd, table, &backup,
|
|
return_check == ERROR_CHECKING_REPOSITORY);
|
|
thd->variables.sql_mode= saved_mode;
|
|
access->drop_thd(thd);
|
|
DBUG_RETURN(return_check);
|
|
}
|
|
|
|
bool Rpl_info_table::do_count_info(uint nparam,
|
|
const char* param_schema,
|
|
const char *param_table,
|
|
uint* counter)
|
|
{
|
|
int error= 1;
|
|
TABLE *table= NULL;
|
|
sql_mode_t saved_mode;
|
|
Open_tables_backup backup;
|
|
Rpl_info_table *info= NULL;
|
|
THD *thd= NULL;
|
|
|
|
DBUG_ENTER("Rpl_info_table::do_count_info");
|
|
|
|
if (!(info= new Rpl_info_table(nparam, param_schema, param_table)))
|
|
DBUG_RETURN(true);
|
|
|
|
thd= info->access->create_thd();
|
|
saved_mode= thd->variables.sql_mode;
|
|
|
|
/*
|
|
Opens and locks the rpl_info table before accessing it.
|
|
*/
|
|
if (info->access->open_table(thd, info->str_schema, info->str_table,
|
|
info->get_number_info(), TL_READ,
|
|
&table, &backup))
|
|
{
|
|
/*
|
|
We cannot simply print out a warning message at this
|
|
point because this may represent a bootstrap.
|
|
*/
|
|
error= 0;
|
|
goto end;
|
|
}
|
|
|
|
/*
|
|
Counts entries in the rpl_info table.
|
|
*/
|
|
if (info->access->count_info(table, counter))
|
|
{
|
|
sql_print_warning("Info table is not ready to be used. Table "
|
|
"'%s.%s' cannot be scanned.", info->str_schema.str,
|
|
info->str_table.str);
|
|
goto end;
|
|
}
|
|
error= 0;
|
|
|
|
end:
|
|
/*
|
|
Unlocks and closes the rpl_info table.
|
|
*/
|
|
error= info->access->close_table(thd, table, &backup, error) || error;
|
|
thd->variables.sql_mode= saved_mode;
|
|
info->access->drop_thd(thd);
|
|
delete info;
|
|
DBUG_RETURN(error);
|
|
}
|
|
|
|
void Rpl_info_table::do_end_info()
|
|
{
|
|
}
|
|
|
|
int Rpl_info_table::do_prepare_info_for_read()
|
|
{
|
|
if (!field_values)
|
|
return TRUE;
|
|
|
|
cursor= 0;
|
|
prv_error= FALSE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
int Rpl_info_table::do_prepare_info_for_write()
|
|
{
|
|
return(do_prepare_info_for_read());
|
|
}
|
|
|
|
uint Rpl_info_table::do_get_rpl_info_type()
|
|
{
|
|
return INFO_REPOSITORY_TABLE;
|
|
}
|
|
|
|
bool Rpl_info_table::do_set_info(const int pos, const char *value)
|
|
{
|
|
return (field_values->value[pos].copy(value, strlen(value),
|
|
&my_charset_bin));
|
|
}
|
|
|
|
bool Rpl_info_table::do_set_info(const int pos, const uchar *value,
|
|
const size_t size)
|
|
{
|
|
return (field_values->value[pos].copy((char *) value, size,
|
|
&my_charset_bin));
|
|
}
|
|
|
|
bool Rpl_info_table::do_set_info(const int pos, const ulong value)
|
|
{
|
|
return (field_values->value[pos].set_int(value, TRUE,
|
|
&my_charset_bin));
|
|
}
|
|
|
|
bool Rpl_info_table::do_set_info(const int pos, const int value)
|
|
{
|
|
return (field_values->value[pos].set_int(value, FALSE,
|
|
&my_charset_bin));
|
|
}
|
|
|
|
bool Rpl_info_table::do_set_info(const int pos, const float value)
|
|
{
|
|
return (field_values->value[pos].set_real(value, NOT_FIXED_DEC,
|
|
&my_charset_bin));
|
|
}
|
|
|
|
bool Rpl_info_table::do_set_info(const int pos, const Server_ids *value)
|
|
{
|
|
if (const_cast<Server_ids*>(value)->pack_dynamic_ids(&field_values->value[pos]))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
bool Rpl_info_table::do_get_info(const int pos, char *value, const size_t size,
|
|
const char *default_value)
|
|
{
|
|
if (field_values->value[pos].length())
|
|
strmake(value, field_values->value[pos].c_ptr_safe(),
|
|
field_values->value[pos].length());
|
|
else if (default_value)
|
|
strmake(value, default_value, strlen(default_value));
|
|
else
|
|
*value= '\0';
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
bool Rpl_info_table::do_get_info(const int pos, uchar *value, const size_t size,
|
|
const uchar *default_value MY_ATTRIBUTE((unused)))
|
|
{
|
|
if (field_values->value[pos].length() == size)
|
|
return (!memcpy((char *) value,
|
|
field_values->value[pos].c_ptr_safe(), size));
|
|
return TRUE;
|
|
}
|
|
|
|
bool Rpl_info_table::do_get_info(const int pos, ulong *value,
|
|
const ulong default_value)
|
|
{
|
|
if (field_values->value[pos].length())
|
|
{
|
|
*value= strtoul(field_values->value[pos].c_ptr_safe(), 0, 10);
|
|
return FALSE;
|
|
}
|
|
else if (default_value)
|
|
{
|
|
*value= default_value;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool Rpl_info_table::do_get_info(const int pos, int *value,
|
|
const int default_value)
|
|
{
|
|
if (field_values->value[pos].length())
|
|
{
|
|
*value= atoi(field_values->value[pos].c_ptr_safe());
|
|
return FALSE;
|
|
}
|
|
else if (default_value)
|
|
{
|
|
*value= default_value;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool Rpl_info_table::do_get_info(const int pos, float *value,
|
|
const float default_value)
|
|
{
|
|
if (field_values->value[pos].length())
|
|
{
|
|
if (sscanf(field_values->value[pos].c_ptr_safe(), "%f", value) != 1)
|
|
return TRUE;
|
|
return FALSE;
|
|
}
|
|
else if (default_value != 0.0)
|
|
{
|
|
*value= default_value;
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
bool Rpl_info_table::do_get_info(const int pos, Server_ids *value,
|
|
const Server_ids *default_value MY_ATTRIBUTE((unused)))
|
|
{
|
|
if (value->unpack_dynamic_ids(field_values->value[pos].c_ptr_safe()))
|
|
return TRUE;
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
char* Rpl_info_table::do_get_description_info()
|
|
{
|
|
return description;
|
|
}
|
|
|
|
bool Rpl_info_table::do_is_transactional()
|
|
{
|
|
return is_transactional;
|
|
}
|
|
|
|
bool Rpl_info_table::do_update_is_transactional()
|
|
{
|
|
bool error= TRUE;
|
|
sql_mode_t saved_mode;
|
|
TABLE *table= NULL;
|
|
Open_tables_backup backup;
|
|
|
|
DBUG_ENTER("Rpl_info_table::do_update_is_transactional");
|
|
DBUG_EXECUTE_IF("simulate_update_is_transactional_error",
|
|
{
|
|
DBUG_RETURN(TRUE);
|
|
});
|
|
|
|
THD *thd= access->create_thd();
|
|
saved_mode= thd->variables.sql_mode;
|
|
tmp_disable_binlog(thd);
|
|
|
|
/*
|
|
Opens and locks the rpl_info table before accessing it.
|
|
*/
|
|
if (access->open_table(thd, str_schema, str_table,
|
|
get_number_info(), TL_READ,
|
|
&table, &backup))
|
|
goto end;
|
|
|
|
is_transactional= table->file->has_transactions();
|
|
error= FALSE;
|
|
|
|
end:
|
|
error= access->close_table(thd, table, &backup, 0) || error;
|
|
reenable_binlog(thd);
|
|
thd->variables.sql_mode= saved_mode;
|
|
access->drop_thd(thd);
|
|
DBUG_RETURN(error);
|
|
}
|
|
|
|
bool Rpl_info_table::verify_table_primary_key_fields(TABLE *table)
|
|
{
|
|
DBUG_ENTER("Rpl_info_table::verify_table_primary_key_fields");
|
|
KEY *key_info= table->key_info;
|
|
bool error;
|
|
|
|
/*
|
|
If the table has no keys or has less key fields than expected,
|
|
it must be corrupted.
|
|
*/
|
|
if ((error= !key_info ||
|
|
key_info->user_defined_key_parts == 0 ||
|
|
(m_n_pk_fields > 0 &&
|
|
key_info->user_defined_key_parts != m_n_pk_fields)))
|
|
{
|
|
sql_print_error("Corrupted table %s.%s. Check out table definition.",
|
|
str_schema.str, str_table.str);
|
|
}
|
|
|
|
if (!error && m_n_pk_fields && m_pk_field_indexes)
|
|
{
|
|
/*
|
|
If any of its primary key fields are not at the expected position,
|
|
the table must be corrupted.
|
|
*/
|
|
for (uint idx= 0; idx < m_n_pk_fields; idx++)
|
|
{
|
|
if (key_info->key_part[idx].field != table->field[m_pk_field_indexes[idx]])
|
|
{
|
|
const char *key_field_name= key_info->key_part[idx].field->field_name;
|
|
const char *table_field_name= table->field[m_pk_field_indexes[idx]]->field_name;
|
|
sql_print_error("Info table has a problem with its key field(s). "
|
|
"Table '%s.%s' expected field #%u to be '%s' but "
|
|
"found '%s' instead.",
|
|
str_schema.str, str_table.str,
|
|
m_pk_field_indexes[idx],
|
|
key_field_name,
|
|
table_field_name);
|
|
error= true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
DBUG_RETURN(error);
|
|
}
|