mirror of
https://github.com/MariaDB/server.git
synced 2025-12-24 11:21:21 +03:00
BUG#53452 Inconsistent behavior of binlog_direct_non_transactional_updates with
temp table
This patch introduces two key changes in the replication's behavior.
Firstly, it reverts part of BUG#51894 which puts any update to temporary tables
into the trx-cache. Now, updates to temporary tables are handled according to
the type of their engines as a regular table.
Secondly, an unsafe mixed statement, (i.e. a statement that access transactional
table as well non-transactional or temporary table, and writes to any of them),
are written into the trx-cache in order to minimize errors in the execution when
the statement logging format is in use.
Such changes has a direct impact on which statements are classified as unsafe
statements and thus part of BUG#53259 is reverted.
This commit is contained in:
355
sql/sql_table.cc
355
sql/sql_table.cc
@@ -1795,6 +1795,8 @@ end:
|
||||
clear_error is clear_error to be called
|
||||
query Query to log
|
||||
query_length Length of query
|
||||
is_trans if the event changes either
|
||||
a trans or non-trans engine.
|
||||
|
||||
RETURN VALUES
|
||||
NONE
|
||||
@@ -1917,18 +1919,64 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
String wrong_tables;
|
||||
int error= 0;
|
||||
int non_temp_tables_count= 0;
|
||||
bool some_tables_deleted=0, tmp_table_deleted=0, foreign_key_error=0;
|
||||
bool foreign_key_error=0;
|
||||
bool non_tmp_error= 0;
|
||||
bool trans_tmp_table_deleted= 0, non_trans_tmp_table_deleted= 0;
|
||||
bool non_tmp_table_deleted= 0;
|
||||
String built_query;
|
||||
String built_tmp_query;
|
||||
String built_trans_tmp_query, built_non_trans_tmp_query;
|
||||
DBUG_ENTER("mysql_rm_table_part2");
|
||||
|
||||
if (thd->is_current_stmt_binlog_format_row() && !dont_log_query)
|
||||
/*
|
||||
Prepares the drop statements that will be written into the binary
|
||||
log as follows:
|
||||
|
||||
1 - If we are not processing a "DROP TEMPORARY" it prepares a
|
||||
"DROP".
|
||||
|
||||
2 - A "DROP" may result in a "DROP TEMPORARY" but the opposite is
|
||||
not true.
|
||||
|
||||
3 - If the current format is row, the IF EXISTS token needs to be
|
||||
appended because one does not know if CREATE TEMPORARY was previously
|
||||
written to the binary log.
|
||||
|
||||
4 - Add the IF_EXISTS token if necessary, i.e. if_exists is TRUE.
|
||||
|
||||
5 - For temporary tables, there is a need to differentiate tables
|
||||
in transactional and non-transactional storage engines. For that,
|
||||
reason, two types of drop statements are prepared.
|
||||
|
||||
The need to different the type of tables when dropping a temporary
|
||||
table stems from the fact that such drop does not commit an ongoing
|
||||
transaction and changes to non-transactional tables must be written
|
||||
ahead of the transaction in some circumstances.
|
||||
*/
|
||||
if (!dont_log_query)
|
||||
{
|
||||
built_query.set_charset(system_charset_info);
|
||||
if (if_exists)
|
||||
built_query.append("DROP TABLE IF EXISTS ");
|
||||
if (!drop_temporary)
|
||||
{
|
||||
built_query.set_charset(system_charset_info);
|
||||
if (if_exists)
|
||||
built_query.append("DROP TABLE IF EXISTS ");
|
||||
else
|
||||
built_query.append("DROP TABLE ");
|
||||
}
|
||||
|
||||
if (thd->is_current_stmt_binlog_format_row() || if_exists)
|
||||
{
|
||||
built_trans_tmp_query.set_charset(system_charset_info);
|
||||
built_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
|
||||
built_non_trans_tmp_query.set_charset(system_charset_info);
|
||||
built_non_trans_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
|
||||
}
|
||||
else
|
||||
built_query.append("DROP TABLE ");
|
||||
{
|
||||
built_trans_tmp_query.set_charset(system_charset_info);
|
||||
built_trans_tmp_query.append("DROP TEMPORARY TABLE ");
|
||||
built_non_trans_tmp_query.set_charset(system_charset_info);
|
||||
built_non_trans_tmp_query.append("DROP TEMPORARY TABLE ");
|
||||
}
|
||||
}
|
||||
|
||||
mysql_ha_rm_tables(thd, tables);
|
||||
@@ -1997,6 +2045,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
|
||||
for (table= tables; table; table= table->next_local)
|
||||
{
|
||||
bool is_trans;
|
||||
char *db=table->db;
|
||||
handlerton *table_type;
|
||||
enum legacy_db_type frm_db_type= DB_TYPE_UNKNOWN;
|
||||
@@ -2005,78 +2054,70 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
table->db, table->table_name, (long) table->table,
|
||||
table->table ? (long) table->table->s : (long) -1));
|
||||
|
||||
/*
|
||||
drop_temporary_table may return one of the following error codes:
|
||||
. 0 - a temporary table was successfully dropped.
|
||||
. 1 - a temporary table was not found.
|
||||
. -1 - a temporary table is used by an outer statement.
|
||||
*/
|
||||
if (table->open_type == OT_BASE_ONLY)
|
||||
error= 1;
|
||||
else
|
||||
error= drop_temporary_table(thd, table);
|
||||
|
||||
switch (error) {
|
||||
case 0:
|
||||
// removed temporary table
|
||||
tmp_table_deleted= 1;
|
||||
/*
|
||||
One needs to always log any temporary table drop if the current
|
||||
statement logging format is set to row. This happens because one
|
||||
might have created a temporary table while the statement logging
|
||||
format was statement and then switched to mixed or row format.
|
||||
*/
|
||||
if (thd->is_current_stmt_binlog_format_row())
|
||||
{
|
||||
if (built_tmp_query.is_empty())
|
||||
{
|
||||
built_tmp_query.set_charset(system_charset_info);
|
||||
built_tmp_query.append("DROP TEMPORARY TABLE IF EXISTS ");
|
||||
}
|
||||
else if ((error= drop_temporary_table(thd, table, &is_trans)) == -1)
|
||||
{
|
||||
DBUG_ASSERT(thd->in_sub_stmt);
|
||||
goto err;
|
||||
}
|
||||
|
||||
built_tmp_query.append("`");
|
||||
if ((drop_temporary && if_exists) || !error)
|
||||
{
|
||||
/*
|
||||
This handles the case of temporary tables. We have the following cases:
|
||||
|
||||
. "DROP TEMPORARY" was executed and a temporary table was affected
|
||||
(i.e. drop_temporary && !error) or the if_exists was specified (i.e.
|
||||
drop_temporary && if_exists).
|
||||
|
||||
. "DROP" was executed but a temporary table was affected (.i.e
|
||||
!error).
|
||||
*/
|
||||
if (!dont_log_query)
|
||||
{
|
||||
/*
|
||||
If there is an error, we don't know the type of the engine
|
||||
at this point. So, we keep it in the trx-cache.
|
||||
*/
|
||||
is_trans= error ? TRUE : is_trans;
|
||||
if (is_trans)
|
||||
trans_tmp_table_deleted= TRUE;
|
||||
else
|
||||
non_trans_tmp_table_deleted= TRUE;
|
||||
|
||||
String *built_ptr_query=
|
||||
(is_trans ? &built_trans_tmp_query : &built_non_trans_tmp_query);
|
||||
/*
|
||||
Don't write the database name if it is the current one (or if
|
||||
thd->db is NULL).
|
||||
*/
|
||||
built_ptr_query->append("`");
|
||||
if (thd->db == NULL || strcmp(db,thd->db) != 0)
|
||||
{
|
||||
built_tmp_query.append(db);
|
||||
built_tmp_query.append("`.`");
|
||||
built_ptr_query->append(db);
|
||||
built_ptr_query->append("`.`");
|
||||
}
|
||||
built_tmp_query.append(table->table_name);
|
||||
built_tmp_query.append("`,");
|
||||
built_ptr_query->append(table->table_name);
|
||||
built_ptr_query->append("`,");
|
||||
}
|
||||
|
||||
continue;
|
||||
case -1:
|
||||
DBUG_ASSERT(thd->in_sub_stmt);
|
||||
error= 1;
|
||||
goto err;
|
||||
default:
|
||||
// temporary table not found
|
||||
error= 0;
|
||||
/*
|
||||
This means that a temporary table was droped and as such there
|
||||
is no need to proceed with the code that tries to drop a regular
|
||||
table.
|
||||
*/
|
||||
if (!error) continue;
|
||||
}
|
||||
|
||||
/* Probably a non-temporary table. */
|
||||
if (!drop_temporary)
|
||||
else if (!drop_temporary)
|
||||
{
|
||||
non_temp_tables_count++;
|
||||
|
||||
/*
|
||||
If row-based replication is used and the table is not a
|
||||
temporary table, we add the table name to the drop statement
|
||||
being built. The string always end in a comma and the comma
|
||||
will be chopped off before being written to the binary log.
|
||||
*/
|
||||
if (!drop_temporary && thd->is_current_stmt_binlog_format_row() && !dont_log_query)
|
||||
{
|
||||
/*
|
||||
Don't write the database name if it is the current one (or if
|
||||
thd->db is NULL).
|
||||
*/
|
||||
built_query.append("`");
|
||||
if (thd->db == NULL || strcmp(db,thd->db) != 0)
|
||||
{
|
||||
built_query.append(db);
|
||||
built_query.append("`.`");
|
||||
}
|
||||
|
||||
built_query.append(table->table_name);
|
||||
built_query.append("`,");
|
||||
}
|
||||
|
||||
if (!drop_temporary)
|
||||
{
|
||||
if (thd->locked_tables_mode)
|
||||
{
|
||||
if (wait_while_table_is_used(thd, table->table, HA_EXTRA_FORCE_REOPEN))
|
||||
@@ -2099,7 +2140,38 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
reg_ext,
|
||||
table->internal_tmp_table ?
|
||||
FN_IS_TMP : 0);
|
||||
|
||||
/*
|
||||
This handles the case where a "DROP" was executed and a regular
|
||||
table "may be" dropped as drop_temporary is FALSE and error is
|
||||
TRUE. If the error was FALSE a temporary table was dropped and
|
||||
regardless of the status of drop_tempoary a "DROP TEMPORARY"
|
||||
must be used.
|
||||
*/
|
||||
if (!dont_log_query)
|
||||
{
|
||||
/*
|
||||
Note that unless if_exists is TRUE or a temporary table was deleted,
|
||||
there is no means to know if the statement should be written to the
|
||||
binary log. See further information on this variable in what follows.
|
||||
*/
|
||||
non_tmp_table_deleted= (if_exists ? TRUE : non_tmp_table_deleted);
|
||||
/*
|
||||
Don't write the database name if it is the current one (or if
|
||||
thd->db is NULL).
|
||||
*/
|
||||
built_query.append("`");
|
||||
if (thd->db == NULL || strcmp(db,thd->db) != 0)
|
||||
{
|
||||
built_query.append(db);
|
||||
built_query.append("`.`");
|
||||
}
|
||||
|
||||
built_query.append(table->table_name);
|
||||
built_query.append("`,");
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
TODO: Investigate what should be done to remove this lock completely.
|
||||
Is exclusive meta-data lock enough ?
|
||||
@@ -2108,19 +2180,29 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
DBUG_EXECUTE_IF("sleep_before_part2_delete_table",
|
||||
my_sleep(100000););
|
||||
mysql_mutex_lock(&LOCK_open);
|
||||
error= 0;
|
||||
if (drop_temporary ||
|
||||
((access(path, F_OK) &&
|
||||
ha_create_table_from_engine(thd, db, alias)) ||
|
||||
(!drop_view &&
|
||||
dd_frm_type(thd, path, &frm_db_type) != FRMTYPE_TABLE)))
|
||||
{
|
||||
// Table was not found on disk and table can't be created from engine
|
||||
/*
|
||||
One of the following cases happened:
|
||||
. "DROP TEMPORARY" but a temporary table was not found.
|
||||
. "DROP" but table was not found on disk and table can't be
|
||||
created from engine.
|
||||
. ./sql/datadict.cc +32 /Alfranio - TODO: We need to test this.
|
||||
*/
|
||||
if (if_exists)
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_BAD_TABLE_ERROR, ER(ER_BAD_TABLE_ERROR),
|
||||
table->table_name);
|
||||
else
|
||||
{
|
||||
non_tmp_error = (drop_temporary ? non_tmp_error : TRUE);
|
||||
error= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -2153,7 +2235,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
if (error == HA_ERR_ROW_IS_REFERENCED)
|
||||
{
|
||||
/* the table is referenced by a foreign key constraint */
|
||||
foreign_key_error=1;
|
||||
foreign_key_error= 1;
|
||||
}
|
||||
if (!error || error == ENOENT || error == HA_ERR_NO_SUCH_TABLE)
|
||||
{
|
||||
@@ -2162,12 +2244,13 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
strmov(end,reg_ext);
|
||||
if (!(new_error= mysql_file_delete(key_file_frm, path, MYF(MY_WME))))
|
||||
{
|
||||
some_tables_deleted=1;
|
||||
non_tmp_table_deleted= TRUE;
|
||||
new_error= Table_triggers_list::drop_all_triggers(thd, db,
|
||||
table->table_name);
|
||||
}
|
||||
error|= new_error;
|
||||
}
|
||||
non_tmp_error= error ? TRUE : non_tmp_error;
|
||||
}
|
||||
mysql_mutex_unlock(&LOCK_open);
|
||||
if (error)
|
||||
@@ -2183,11 +2266,12 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
my_printf_error(ER_BAD_TABLE_ERROR,
|
||||
ER(ER_BAD_TABLE_ERROR), MYF(0),
|
||||
table->table_name););
|
||||
|
||||
}
|
||||
DEBUG_SYNC(thd, "rm_table_part2_before_binlog");
|
||||
thd->thread_specific_used|= tmp_table_deleted;
|
||||
thd->thread_specific_used|= (trans_tmp_table_deleted ||
|
||||
non_trans_tmp_table_deleted);
|
||||
error= 0;
|
||||
err:
|
||||
if (wrong_tables.length())
|
||||
{
|
||||
if (!foreign_key_error)
|
||||
@@ -2198,85 +2282,48 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
|
||||
error= 1;
|
||||
}
|
||||
|
||||
if (some_tables_deleted || tmp_table_deleted || !error)
|
||||
if (non_trans_tmp_table_deleted ||
|
||||
trans_tmp_table_deleted || non_tmp_table_deleted)
|
||||
{
|
||||
query_cache_invalidate3(thd, tables, 0);
|
||||
if (!dont_log_query && mysql_bin_log.is_open())
|
||||
{
|
||||
if (!thd->is_current_stmt_binlog_format_row() ||
|
||||
(non_temp_tables_count > 0 && !tmp_table_deleted))
|
||||
if (non_trans_tmp_table_deleted)
|
||||
{
|
||||
/*
|
||||
In this case, we are either using statement-based
|
||||
replication or using row-based replication but have only
|
||||
deleted one or more non-temporary tables (and no temporary
|
||||
tables). In this case, we can write the original query into
|
||||
the binary log.
|
||||
*/
|
||||
error |= write_bin_log(thd, !error, thd->query(), thd->query_length());
|
||||
/* Chop of the last comma */
|
||||
built_non_trans_tmp_query.chop();
|
||||
built_non_trans_tmp_query.append(" /* generated by server */");
|
||||
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
|
||||
built_non_trans_tmp_query.ptr(),
|
||||
built_non_trans_tmp_query.length(),
|
||||
FALSE, FALSE, FALSE, 0);
|
||||
}
|
||||
else if (thd->is_current_stmt_binlog_format_row() &&
|
||||
tmp_table_deleted)
|
||||
if (trans_tmp_table_deleted)
|
||||
{
|
||||
if (non_temp_tables_count > 0)
|
||||
{
|
||||
/*
|
||||
In this case we have deleted both temporary and
|
||||
non-temporary tables, so:
|
||||
- since we have deleted a non-temporary table we have to
|
||||
binlog the statement, but
|
||||
- since we have deleted a temporary table we cannot binlog
|
||||
the statement (since the table may have not been created on the
|
||||
slave - check "if" branch below, this might cause the slave to
|
||||
stop).
|
||||
|
||||
Instead, we write a built statement, only containing the
|
||||
non-temporary tables, to the binary log
|
||||
*/
|
||||
built_query.chop(); // Chop of the last comma
|
||||
/* Chop of the last comma */
|
||||
built_trans_tmp_query.chop();
|
||||
built_trans_tmp_query.append(" /* generated by server */");
|
||||
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
|
||||
built_trans_tmp_query.ptr(),
|
||||
built_trans_tmp_query.length(),
|
||||
TRUE, FALSE, FALSE, 0);
|
||||
}
|
||||
if (non_tmp_table_deleted)
|
||||
{
|
||||
/* Chop of the last comma */
|
||||
built_query.chop();
|
||||
built_query.append(" /* generated by server */");
|
||||
error|= write_bin_log(thd, !error, built_query.ptr(), built_query.length());
|
||||
}
|
||||
|
||||
/*
|
||||
One needs to always log any temporary table drop if the current
|
||||
statement logging format is set to row. This happens because one
|
||||
might have created a temporary table while the statement logging
|
||||
format was statement and then switched to mixed or row format.
|
||||
*/
|
||||
if (thd->is_current_stmt_binlog_format_row())
|
||||
{
|
||||
/*
|
||||
In this case we have deleted some temporary tables but we are using
|
||||
row based logging for the statement. However, thread uses mixed mode
|
||||
format, thence we need to log the dropping as we cannot tell for
|
||||
sure whether the create was logged as statement previously or not, ie,
|
||||
before switching to row mode.
|
||||
*/
|
||||
built_tmp_query.chop(); // Chop of the last comma
|
||||
built_tmp_query.append(" /* generated by server */");
|
||||
/*
|
||||
We cannot call the write_bin_log as we do not care about any errors
|
||||
in the master as the statement is always DROP TEMPORARY TABLE IF EXISTS
|
||||
and as such there will be no errors in the slave.
|
||||
*/
|
||||
error|= thd->binlog_query(THD::STMT_QUERY_TYPE, built_tmp_query.ptr(),
|
||||
built_tmp_query.length(), FALSE, FALSE, FALSE,
|
||||
0);
|
||||
}
|
||||
int error_code = (non_tmp_error ?
|
||||
(foreign_key_error ? ER_ROW_IS_REFERENCED : ER_BAD_TABLE_ERROR) : 0);
|
||||
error |= thd->binlog_query(THD::STMT_QUERY_TYPE,
|
||||
built_query.ptr(),
|
||||
built_query.length(),
|
||||
TRUE, FALSE, FALSE,
|
||||
error_code);
|
||||
}
|
||||
|
||||
/*
|
||||
The remaining cases are:
|
||||
- no tables were deleted and
|
||||
- only temporary tables were deleted and row-based
|
||||
replication is used.
|
||||
In both these cases, nothing should be written to the binary
|
||||
log.
|
||||
*/
|
||||
}
|
||||
}
|
||||
err:
|
||||
|
||||
if (!drop_temporary)
|
||||
{
|
||||
/*
|
||||
@@ -3791,6 +3838,8 @@ void sp_prepare_create_field(THD *thd, Create_field *sql_field)
|
||||
internal_tmp_table Set to 1 if this is an internal temporary table
|
||||
(From ALTER TABLE)
|
||||
select_field_count
|
||||
is_trans identifies the type of engine where the table
|
||||
was created: either trans or non-trans.
|
||||
|
||||
DESCRIPTION
|
||||
If one creates a temporary table, this is automatically opened
|
||||
@@ -3815,7 +3864,8 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
HA_CREATE_INFO *create_info,
|
||||
Alter_info *alter_info,
|
||||
bool internal_tmp_table,
|
||||
uint select_field_count)
|
||||
uint select_field_count,
|
||||
bool *is_trans)
|
||||
{
|
||||
char path[FN_REFLEN + 1];
|
||||
uint path_length;
|
||||
@@ -4180,12 +4230,17 @@ bool mysql_create_table_no_lock(THD *thd,
|
||||
|
||||
if (create_info->options & HA_LEX_CREATE_TMP_TABLE)
|
||||
{
|
||||
TABLE *table= NULL;
|
||||
/* Open table and put in temporary table list */
|
||||
if (!(open_temporary_table(thd, path, db, table_name, 1)))
|
||||
if (!(table= open_temporary_table(thd, path, db, table_name, 1)))
|
||||
{
|
||||
(void) rm_temporary_table(create_info->db_type, path);
|
||||
goto unlock_and_end;
|
||||
}
|
||||
|
||||
if (is_trans != NULL)
|
||||
*is_trans= table->file->has_transactions();
|
||||
|
||||
thd->thread_specific_used= TRUE;
|
||||
}
|
||||
|
||||
@@ -4236,9 +4291,10 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
|
||||
/* Got lock. */
|
||||
DEBUG_SYNC(thd, "locked_table_name");
|
||||
|
||||
bool is_trans;
|
||||
result= mysql_create_table_no_lock(thd, create_table->db,
|
||||
create_table->table_name, create_info,
|
||||
alter_info, FALSE, 0);
|
||||
alter_info, FALSE, 0, &is_trans);
|
||||
|
||||
/*
|
||||
Don't write statement if:
|
||||
@@ -4250,7 +4306,7 @@ bool mysql_create_table(THD *thd, TABLE_LIST *create_table,
|
||||
(!thd->is_current_stmt_binlog_format_row() ||
|
||||
(thd->is_current_stmt_binlog_format_row() &&
|
||||
!(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
|
||||
result= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
|
||||
result= write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans);
|
||||
|
||||
end:
|
||||
DBUG_RETURN(result);
|
||||
@@ -4456,9 +4512,10 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
/* Reset auto-increment counter for the new table. */
|
||||
local_create_info.auto_increment_value= 0;
|
||||
|
||||
bool is_trans;
|
||||
if ((res= mysql_create_table_no_lock(thd, table->db, table->table_name,
|
||||
&local_create_info, &local_alter_info,
|
||||
FALSE, 0)))
|
||||
FALSE, 0, &is_trans)))
|
||||
goto err;
|
||||
|
||||
/*
|
||||
@@ -4539,7 +4596,7 @@ bool mysql_create_like_table(THD* thd, TABLE_LIST* table, TABLE_LIST* src_table,
|
||||
Case 3 and 4 does nothing under RBR
|
||||
*/
|
||||
}
|
||||
else if (write_bin_log(thd, TRUE, thd->query(), thd->query_length()))
|
||||
else if (write_bin_log(thd, TRUE, thd->query(), thd->query_length(), is_trans))
|
||||
goto err;
|
||||
|
||||
err:
|
||||
@@ -6228,7 +6285,7 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
|
||||
error= mysql_create_table_no_lock(thd, new_db, tmp_name,
|
||||
create_info,
|
||||
alter_info,
|
||||
1, 0);
|
||||
1, 0, NULL);
|
||||
reenable_binlog(thd);
|
||||
if (error)
|
||||
goto err;
|
||||
|
||||
Reference in New Issue
Block a user