mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
Merge bk-internal.mysql.com:/home/bk/mysql-5.1
into vajra.(none):/opt/local/work/mysql-5.1-runtime mysql-test/include/mix1.inc: Auto merged mysql-test/r/innodb_mysql.result: Auto merged mysql-test/r/ps_1general.result: Auto merged mysql-test/t/disabled.def: Auto merged mysql-test/t/ps_1general.test: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/ha_ndbcluster_binlog.cc: Auto merged sql/item.cc: Auto merged sql/item_func.cc: Auto merged sql/mysql_priv.h: Auto merged sql/set_var.cc: Auto merged sql/sql_base.cc: Auto merged sql/sql_cache.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_class.h: Auto merged sql/sql_lex.cc: Auto merged sql/sql_lex.h: Auto merged sql/sql_parse.cc: Auto merged sql/sql_partition.cc: Auto merged sql/sql_prepare.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_yacc.yy: Auto merged sql/table.h: Auto merged sql/sql_insert.cc: SCCS merged
This commit is contained in:
@ -29,7 +29,7 @@
|
||||
waited for to open and lock the table.
|
||||
|
||||
If accessing the thread succeeded, in
|
||||
delayed_insert::get_local_table() the table of the thread is copied
|
||||
Delayed_insert::get_local_table() the table of the thread is copied
|
||||
for local use. A copy is required because the normal insert logic
|
||||
works on a target table, but the other threads table object must not
|
||||
be used. The insert logic uses the record buffer to create a record.
|
||||
@ -384,6 +384,88 @@ void prepare_triggers_for_insert_stmt(TABLE *table)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Upgrade table-level lock of INSERT statement to TL_WRITE if
|
||||
a more concurrent lock is infeasible for some reason. This is
|
||||
necessary for engines without internal locking support (MyISAM).
|
||||
An engine with internal locking implementation might later
|
||||
downgrade the lock in handler::store_lock() method.
|
||||
*/
|
||||
|
||||
void upgrade_lock_type(THD *thd, thr_lock_type *lock_type,
|
||||
enum_duplicates duplic,
|
||||
bool is_multi_insert)
|
||||
{
|
||||
if (duplic == DUP_UPDATE ||
|
||||
duplic == DUP_REPLACE && *lock_type == TL_WRITE_CONCURRENT_INSERT)
|
||||
{
|
||||
*lock_type= TL_WRITE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (*lock_type == TL_WRITE_DELAYED)
|
||||
{
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
/* No auxiliary threads in the embedded server. */
|
||||
*lock_type= TL_WRITE;
|
||||
return;
|
||||
#else
|
||||
/*
|
||||
We do not use delayed threads if:
|
||||
- we're running in the safe mode or skip-new - the feature
|
||||
is disabled in these modes
|
||||
- we're running this query in statement level replication,
|
||||
on a replication slave - because we must ensure serial
|
||||
execution of queries on the slave
|
||||
- it is INSERT .. ON DUPLICATE KEY UPDATE - in this case the
|
||||
insert cannot be concurrent
|
||||
*/
|
||||
if (specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE) ||
|
||||
thd->slave_thread ||
|
||||
thd->variables.max_insert_delayed_threads == 0)
|
||||
{
|
||||
*lock_type= TL_WRITE;
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
bool log_on= (thd->options & OPTION_BIN_LOG ||
|
||||
! (thd->security_ctx->master_access & SUPER_ACL));
|
||||
if (global_system_variables.binlog_format == BINLOG_FORMAT_STMT &&
|
||||
log_on && mysql_bin_log.is_open() && is_multi_insert)
|
||||
{
|
||||
/*
|
||||
Statement-based binary logging does not work in this case, because:
|
||||
a) two concurrent statements may have their rows intermixed in the
|
||||
queue, leading to autoincrement replication problems on slave (because
|
||||
the values generated used for one statement don't depend only on the
|
||||
value generated for the first row of this statement, so are not
|
||||
replicable)
|
||||
b) if first row of the statement has an error the full statement is
|
||||
not binlogged, while next rows of the statement may be inserted.
|
||||
c) if first row succeeds, statement is binlogged immediately with a
|
||||
zero error code (i.e. "no error"), if then second row fails, query
|
||||
will fail on slave too and slave will stop (wrongly believing that the
|
||||
master got no error).
|
||||
So we fallback to non-delayed INSERT.
|
||||
Note that to be fully correct, we should test the "binlog format which
|
||||
the delayed thread is going to use for this row". But in the common case
|
||||
where the global binlog format is not changed and the session binlog
|
||||
format may be changed, that is equal to the global binlog format.
|
||||
We test it without mutex for speed reasons (condition rarely true), and
|
||||
in the common case (global not changed) it is as good as without mutex;
|
||||
if global value is changed, anyway there is uncertainty as the delayed
|
||||
thread may be old and use the before-the-change value.
|
||||
*/
|
||||
*lock_type= TL_WRITE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
INSERT statement implementation
|
||||
*/
|
||||
|
||||
bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
List<Item> &fields,
|
||||
List<List_item> &values_list,
|
||||
@ -406,7 +488,6 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
Name_resolution_context_state ctx_state;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
char *query= thd->query;
|
||||
#endif
|
||||
/*
|
||||
log_on is about delayed inserts only.
|
||||
By default, both logs are enabled (this won't cause problems if the server
|
||||
@ -414,72 +495,37 @@ bool mysql_insert(THD *thd,TABLE_LIST *table_list,
|
||||
*/
|
||||
bool log_on= ((thd->options & OPTION_BIN_LOG) ||
|
||||
(!(thd->security_ctx->master_access & SUPER_ACL)));
|
||||
#endif
|
||||
thr_lock_type lock_type = table_list->lock_type;
|
||||
Item *unused_conds= 0;
|
||||
DBUG_ENTER("mysql_insert");
|
||||
|
||||
/*
|
||||
in safe mode or with skip-new change delayed insert to be regular
|
||||
if we are told to replace duplicates, the insert cannot be concurrent
|
||||
delayed insert changed to regular in slave thread
|
||||
*/
|
||||
#ifdef EMBEDDED_LIBRARY
|
||||
if (lock_type == TL_WRITE_DELAYED)
|
||||
lock_type=TL_WRITE;
|
||||
#else
|
||||
if ((lock_type == TL_WRITE_DELAYED &&
|
||||
((specialflag & (SPECIAL_NO_NEW_FUNC | SPECIAL_SAFE_MODE)) ||
|
||||
thd->slave_thread || !thd->variables.max_insert_delayed_threads)) ||
|
||||
(lock_type == TL_WRITE_CONCURRENT_INSERT && duplic == DUP_REPLACE) ||
|
||||
(duplic == DUP_UPDATE))
|
||||
lock_type=TL_WRITE;
|
||||
#endif
|
||||
if ((lock_type == TL_WRITE_DELAYED) &&
|
||||
(global_system_variables.binlog_format == BINLOG_FORMAT_STMT) &&
|
||||
log_on && mysql_bin_log.is_open() &&
|
||||
(values_list.elements > 1))
|
||||
Upgrade lock type if the requested lock is incompatible with
|
||||
the current connection mode or table operation.
|
||||
*/
|
||||
upgrade_lock_type(thd, &table_list->lock_type, duplic,
|
||||
values_list.elements > 1);
|
||||
lock_type= table_list->lock_type;
|
||||
|
||||
/*
|
||||
We can't write-delayed into a table locked with LOCK TABLES:
|
||||
this will lead to a deadlock, since the delayed thread will
|
||||
never be able to get a lock on the table. QQQ: why not
|
||||
upgrade the lock here instead?
|
||||
*/
|
||||
if (lock_type == TL_WRITE_DELAYED && thd->locked_tables &&
|
||||
find_locked_table(thd, table_list->db, table_list->table_name))
|
||||
{
|
||||
/*
|
||||
Statement-based binary logging does not work in this case, because:
|
||||
a) two concurrent statements may have their rows intermixed in the
|
||||
queue, leading to autoincrement replication problems on slave (because
|
||||
the values generated used for one statement don't depend only on the
|
||||
value generated for the first row of this statement, so are not
|
||||
replicable)
|
||||
b) if first row of the statement has an error the full statement is
|
||||
not binlogged, while next rows of the statement may be inserted.
|
||||
c) if first row succeeds, statement is binlogged immediately with a
|
||||
zero error code (i.e. "no error"), if then second row fails, query
|
||||
will fail on slave too and slave will stop (wrongly believing that the
|
||||
master got no error).
|
||||
So we fallback to non-delayed INSERT.
|
||||
Note that to be fully correct, we should test the "binlog format which
|
||||
the delayed thread is going to use for this row". But in the common case
|
||||
where the global binlog format is not changed and the session binlog
|
||||
format may be changed, that is equal to the global binlog format.
|
||||
We test it without mutex for speed reasons (condition rarely true), and
|
||||
in the common case (global not changed) it is as good as without mutex;
|
||||
if global value is changed, anyway there is uncertainty as the delayed
|
||||
thread may be old and use the before-the-change value.
|
||||
*/
|
||||
lock_type= TL_WRITE;
|
||||
my_error(ER_DELAYED_INSERT_TABLE_LOCKED, MYF(0),
|
||||
table_list->table_name);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
table_list->lock_type= lock_type;
|
||||
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
if (lock_type == TL_WRITE_DELAYED)
|
||||
{
|
||||
res= 1;
|
||||
if (thd->locked_tables)
|
||||
{
|
||||
DBUG_ASSERT(table_list->db); /* Must be set in the parser */
|
||||
if (find_locked_table(thd, table_list->db, table_list->table_name))
|
||||
{
|
||||
my_error(ER_DELAYED_INSERT_TABLE_LOCKED, MYF(0),
|
||||
table_list->table_name);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
if ((table= delayed_get_table(thd,table_list)) && !thd->is_fatal_error)
|
||||
{
|
||||
/*
|
||||
@ -1503,8 +1549,14 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
Delayed_insert - context of a thread responsible for delayed insert
|
||||
into one table. When processing delayed inserts, we create an own
|
||||
thread for every distinct table. Later on all delayed inserts directed
|
||||
into that table are handled by a dedicated thread.
|
||||
*/
|
||||
|
||||
class delayed_insert :public ilink {
|
||||
class Delayed_insert :public ilink {
|
||||
uint locks_in_memory;
|
||||
public:
|
||||
THD thd;
|
||||
@ -1518,7 +1570,7 @@ public:
|
||||
ulong group_count;
|
||||
TABLE_LIST table_list; // Argument
|
||||
|
||||
delayed_insert()
|
||||
Delayed_insert()
|
||||
:locks_in_memory(0),
|
||||
table(0),tables_in_use(0),stacked_inserts(0), status(0), dead(0),
|
||||
group_count(0)
|
||||
@ -1548,7 +1600,7 @@ public:
|
||||
delayed_insert_threads++;
|
||||
VOID(pthread_mutex_unlock(&LOCK_thread_count));
|
||||
}
|
||||
~delayed_insert()
|
||||
~Delayed_insert()
|
||||
{
|
||||
/* The following is not really needed, but just for safety */
|
||||
delayed_row *row;
|
||||
@ -1596,15 +1648,21 @@ public:
|
||||
};
|
||||
|
||||
|
||||
I_List<delayed_insert> delayed_threads;
|
||||
I_List<Delayed_insert> delayed_threads;
|
||||
|
||||
|
||||
delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
|
||||
/**
|
||||
Return an instance of delayed insert thread that can handle
|
||||
inserts into a given table, if it exists. Otherwise return NULL.
|
||||
*/
|
||||
|
||||
static
|
||||
Delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
|
||||
{
|
||||
thd->proc_info="waiting for delay_list";
|
||||
pthread_mutex_lock(&LOCK_delayed_insert); // Protect master list
|
||||
I_List_iterator<delayed_insert> it(delayed_threads);
|
||||
delayed_insert *tmp;
|
||||
I_List_iterator<Delayed_insert> it(delayed_threads);
|
||||
Delayed_insert *tmp;
|
||||
while ((tmp=it++))
|
||||
{
|
||||
if (!strcmp(tmp->thd.db, table_list->db) &&
|
||||
@ -1619,10 +1677,22 @@ delayed_insert *find_handler(THD *thd, TABLE_LIST *table_list)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Attempt to find or create a delayed insert thread to handle inserts
|
||||
into this table.
|
||||
|
||||
@return Return a local copy of the table in the delayed thread
|
||||
@retval NULL too many delayed threads OR
|
||||
this thread ran out of resources OR
|
||||
a newly created delayed insert thread ran out of resources OR
|
||||
the delayed insert thread failed to open the table.
|
||||
In the last three cases an error is set in THD.
|
||||
*/
|
||||
|
||||
static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
|
||||
{
|
||||
int error;
|
||||
delayed_insert *tmp;
|
||||
Delayed_insert *tmp;
|
||||
TABLE *table;
|
||||
DBUG_ENTER("delayed_get_table");
|
||||
|
||||
@ -1646,9 +1716,9 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
|
||||
*/
|
||||
if (! (tmp= find_handler(thd, table_list)))
|
||||
{
|
||||
if (!(tmp=new delayed_insert()))
|
||||
if (!(tmp=new Delayed_insert()))
|
||||
{
|
||||
my_error(ER_OUTOFMEMORY,MYF(0),sizeof(delayed_insert));
|
||||
my_error(ER_OUTOFMEMORY,MYF(0),sizeof(Delayed_insert));
|
||||
goto err1;
|
||||
}
|
||||
pthread_mutex_lock(&LOCK_thread_count);
|
||||
@ -1727,21 +1797,27 @@ static TABLE *delayed_get_table(THD *thd,TABLE_LIST *table_list)
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
As we can't let many threads modify the same TABLE structure, we create
|
||||
an own structure for each tread. This includes a row buffer to save the
|
||||
column values and new fields that points to the new row buffer.
|
||||
The memory is allocated in the client thread and is freed automaticly.
|
||||
/**
|
||||
As we can't let many client threads modify the same TABLE
|
||||
structure of the dedicated delayed insert thread, we create an
|
||||
own structure for each client thread. This includes a row
|
||||
buffer to save the column values and new fields that point to
|
||||
the new row buffer. The memory is allocated in the client
|
||||
thread and is freed automatically.
|
||||
|
||||
@pre This function is called from the client thread. Delayed
|
||||
insert thread mutex must be acquired before invoking this
|
||||
function.
|
||||
*/
|
||||
|
||||
TABLE *delayed_insert::get_local_table(THD* client_thd)
|
||||
TABLE *Delayed_insert::get_local_table(THD* client_thd)
|
||||
{
|
||||
my_ptrdiff_t adjust_ptrs;
|
||||
Field **field,**org_field, *found_next_number_field;
|
||||
TABLE *copy;
|
||||
TABLE_SHARE *share= table->s;
|
||||
byte *bitmap;
|
||||
DBUG_ENTER("delayed_insert::get_local_table");
|
||||
DBUG_ENTER("Delayed_insert::get_local_table");
|
||||
|
||||
/* First request insert thread to get a lock */
|
||||
status=1;
|
||||
@ -1851,7 +1927,7 @@ write_delayed(THD *thd,TABLE *table, enum_duplicates duplic,
|
||||
LEX_STRING query, bool ignore, bool log_on)
|
||||
{
|
||||
delayed_row *row= 0;
|
||||
delayed_insert *di=thd->di;
|
||||
Delayed_insert *di=thd->di;
|
||||
const Discrete_interval *forced_auto_inc;
|
||||
DBUG_ENTER("write_delayed");
|
||||
DBUG_PRINT("enter", ("query = '%s' length %u", query.str, query.length));
|
||||
@ -1934,7 +2010,7 @@ write_delayed(THD *thd,TABLE *table, enum_duplicates duplic,
|
||||
static void end_delayed_insert(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("end_delayed_insert");
|
||||
delayed_insert *di=thd->di;
|
||||
Delayed_insert *di=thd->di;
|
||||
pthread_mutex_lock(&di->mutex);
|
||||
DBUG_PRINT("info",("tables in use: %d",di->tables_in_use));
|
||||
if (!--di->tables_in_use || di->thd.killed)
|
||||
@ -1953,8 +2029,8 @@ void kill_delayed_threads(void)
|
||||
{
|
||||
VOID(pthread_mutex_lock(&LOCK_delayed_insert)); // For unlink from list
|
||||
|
||||
I_List_iterator<delayed_insert> it(delayed_threads);
|
||||
delayed_insert *tmp;
|
||||
I_List_iterator<Delayed_insert> it(delayed_threads);
|
||||
Delayed_insert *tmp;
|
||||
while ((tmp=it++))
|
||||
{
|
||||
tmp->thd.killed= THD::KILL_CONNECTION;
|
||||
@ -1986,7 +2062,7 @@ void kill_delayed_threads(void)
|
||||
|
||||
pthread_handler_t handle_delayed_insert(void *arg)
|
||||
{
|
||||
delayed_insert *di=(delayed_insert*) arg;
|
||||
Delayed_insert *di=(Delayed_insert*) arg;
|
||||
THD *thd= &di->thd;
|
||||
|
||||
pthread_detach_this_thread();
|
||||
@ -2237,7 +2313,7 @@ static void free_delayed_insert_blobs(register TABLE *table)
|
||||
}
|
||||
|
||||
|
||||
bool delayed_insert::handle_inserts(void)
|
||||
bool Delayed_insert::handle_inserts(void)
|
||||
{
|
||||
int error;
|
||||
ulong max_rows;
|
||||
@ -2262,7 +2338,7 @@ bool delayed_insert::handle_inserts(void)
|
||||
|
||||
thd.proc_info="insert";
|
||||
max_rows= delayed_insert_limit;
|
||||
if (thd.killed || table->s->version != refresh_version)
|
||||
if (thd.killed || table->needs_reopen_or_name_lock())
|
||||
{
|
||||
thd.killed= THD::KILL_CONNECTION;
|
||||
max_rows= ULONG_MAX; // Do as much as possible
|
||||
@ -2963,8 +3039,8 @@ bool select_insert::send_eof()
|
||||
***************************************************************************/
|
||||
|
||||
/*
|
||||
Create table from lists of fields and items (or open existing table
|
||||
with same name).
|
||||
Create table from lists of fields and items (or just return TABLE
|
||||
object for pre-opened existing table).
|
||||
|
||||
SYNOPSIS
|
||||
create_table_from_items()
|
||||
@ -2979,19 +3055,25 @@ bool select_insert::send_eof()
|
||||
of fields for the table (corresponding fields will
|
||||
be added to the end of 'extra_fields' list)
|
||||
lock out Pointer to the MYSQL_LOCK object for table created
|
||||
(open) will be returned in this parameter. Since
|
||||
this table is not included in THD::lock caller is
|
||||
responsible for explicitly unlocking this table.
|
||||
(or open temporary table) will be returned in this
|
||||
parameter. Since this table is not included in
|
||||
THD::lock caller is responsible for explicitly
|
||||
unlocking this table.
|
||||
hooks
|
||||
|
||||
NOTES
|
||||
If 'create_info->options' bitmask has HA_LEX_CREATE_IF_NOT_EXISTS
|
||||
flag and table with name provided already exists then this function will
|
||||
simply open existing table.
|
||||
Also note that create, open and lock sequence in this function is not
|
||||
atomic and thus contains gap for deadlock and can cause other troubles.
|
||||
Since this function contains some logic specific to CREATE TABLE ... SELECT
|
||||
it should be changed before it can be used in other contexts.
|
||||
This function behaves differently for base and temporary tables:
|
||||
- For base table we assume that either table exists and was pre-opened
|
||||
and locked at open_and_lock_tables() stage (and in this case we just
|
||||
emit error or warning and return pre-opened TABLE object) or special
|
||||
placeholder was put in table cache that guarantees that this table
|
||||
won't be created or opened until the placeholder will be removed
|
||||
(so there is an exclusive lock on this table).
|
||||
- We don't pre-open existing temporary table, instead we either open
|
||||
or create and then open table in this function.
|
||||
|
||||
Since this function contains some logic specific to CREATE TABLE ...
|
||||
SELECT it should be changed before it can be used in other contexts.
|
||||
|
||||
RETURN VALUES
|
||||
non-zero Pointer to TABLE object for table created or opened
|
||||
@ -3017,6 +3099,25 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
||||
bool not_used;
|
||||
DBUG_ENTER("create_table_from_items");
|
||||
|
||||
DBUG_EXECUTE_IF("sleep_create_select_before_check_if_exists", my_sleep(6000000););
|
||||
|
||||
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE) &&
|
||||
create_table->table->db_stat)
|
||||
{
|
||||
/* Table already exists and was open at open_and_lock_tables() stage. */
|
||||
if (create_info->options & HA_LEX_CREATE_IF_NOT_EXISTS)
|
||||
{
|
||||
create_info->table_existed= 1; // Mark that table existed
|
||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||
ER_TABLE_EXISTS_ERROR, ER(ER_TABLE_EXISTS_ERROR),
|
||||
create_table->table_name);
|
||||
DBUG_RETURN(create_table->table);
|
||||
}
|
||||
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
tmp_table.alias= 0;
|
||||
tmp_table.timestamp_field= 0;
|
||||
tmp_table.s= &share;
|
||||
@ -3048,8 +3149,15 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
||||
cr_field->flags &= ~NOT_NULL_FLAG;
|
||||
extra_fields->push_back(cr_field);
|
||||
}
|
||||
|
||||
DBUG_EXECUTE_IF("sleep_create_select_before_create", my_sleep(6000000););
|
||||
|
||||
/*
|
||||
create and lock table
|
||||
Create and lock table.
|
||||
|
||||
Note that we either creating (or opening existing) temporary table or
|
||||
creating base table on which name we have exclusive lock. So code below
|
||||
should not cause deadlocks or races.
|
||||
|
||||
We don't log the statement, it will be logged later.
|
||||
|
||||
@ -3059,63 +3167,74 @@ static TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
||||
don't want to delete from it) 2) it would be written before the CREATE
|
||||
TABLE, which is a wrong order. So we keep binary logging disabled when we
|
||||
open_table().
|
||||
NOTE: By locking table which we just have created (or for which we just
|
||||
have have found that it already exists) separately from other tables used
|
||||
by the statement we create potential window for deadlock.
|
||||
TODO: create and open should be done atomic !
|
||||
*/
|
||||
{
|
||||
tmp_disable_binlog(thd);
|
||||
if (!mysql_create_table(thd, create_table->db, create_table->table_name,
|
||||
create_info, *extra_fields, *keys, 0,
|
||||
select_field_count, 0))
|
||||
if (!mysql_create_table_no_lock(thd, create_table->db,
|
||||
create_table->table_name,
|
||||
create_info, *extra_fields, *keys, 0,
|
||||
select_field_count, 0))
|
||||
{
|
||||
/*
|
||||
If we are here in prelocked mode we either create temporary table
|
||||
or prelocked mode is caused by the SELECT part of this statement.
|
||||
*/
|
||||
DBUG_ASSERT(!thd->prelocked_mode ||
|
||||
create_info->options & HA_LEX_CREATE_TMP_TABLE ||
|
||||
thd->lex->requires_prelocking());
|
||||
|
||||
/*
|
||||
NOTE: We don't want to ignore set of locked tables here if we are
|
||||
under explicit LOCK TABLES since it will open gap for deadlock
|
||||
too wide (and also is not backward compatible).
|
||||
*/
|
||||
if (create_info->table_existed &&
|
||||
!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
|
||||
{
|
||||
/*
|
||||
This means that someone created table underneath server
|
||||
or it was created via different mysqld front-end to the
|
||||
cluster. We don't have much options but throw an error.
|
||||
*/
|
||||
my_error(ER_TABLE_EXISTS_ERROR, MYF(0), create_table->table_name);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
DBUG_EXECUTE_IF("sleep_create_select_before_open", my_sleep(6000000););
|
||||
|
||||
if (!(create_info->options & HA_LEX_CREATE_TMP_TABLE))
|
||||
{
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
if (reopen_name_locked_table(thd, create_table, FALSE))
|
||||
{
|
||||
quick_rm_table(create_info->db_type, create_table->db,
|
||||
table_case_name(create_info, create_table->table_name),
|
||||
0);
|
||||
}
|
||||
else
|
||||
table= create_table->table;
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(table= open_table(thd, create_table, thd->mem_root, (bool*) 0,
|
||||
MYSQL_OPEN_TEMPORARY_ONLY)) &&
|
||||
!create_info->table_existed)
|
||||
{
|
||||
/*
|
||||
This shouldn't happen as creation of temporary table should make
|
||||
it preparable for open. But let us do close_temporary_table() here
|
||||
just in case.
|
||||
*/
|
||||
close_temporary_table(thd, create_table);
|
||||
}
|
||||
}
|
||||
|
||||
if (! (table= open_table(thd, create_table, thd->mem_root, (bool*) 0,
|
||||
(MYSQL_LOCK_IGNORE_FLUSH |
|
||||
((thd->prelocked_mode == PRELOCKED) ?
|
||||
MYSQL_OPEN_IGNORE_LOCKED_TABLES:0)))))
|
||||
quick_rm_table(create_info->db_type, create_table->db,
|
||||
table_case_name(create_info, create_table->table_name),
|
||||
0);
|
||||
}
|
||||
reenable_binlog(thd);
|
||||
if (!table) // open failed
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*
|
||||
FIXME: What happens if trigger manages to be created while we are
|
||||
obtaining this lock ? May be it is sensible just to disable
|
||||
trigger execution in this case ? Or will MYSQL_LOCK_IGNORE_FLUSH
|
||||
save us from that ?
|
||||
*/
|
||||
DBUG_EXECUTE_IF("sleep_create_select_before_lock", my_sleep(6000000););
|
||||
|
||||
table->reginfo.lock_type=TL_WRITE;
|
||||
hooks->prelock(&table, 1); // Call prelock hooks
|
||||
if (! ((*lock)= mysql_lock_tables(thd, &table, 1,
|
||||
MYSQL_LOCK_IGNORE_FLUSH, ¬_used)))
|
||||
{
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
hash_delete(&open_cache,(byte*) table);
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
quick_rm_table(create_info->db_type, create_table->db,
|
||||
table_case_name(create_info, create_table->table_name), 0);
|
||||
if (!create_info->table_existed)
|
||||
drop_open_table(thd, table, create_table->db, create_table->table_name);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
DBUG_RETURN(table);
|
||||
}
|
||||
|
||||
@ -3218,6 +3337,7 @@ select_create::prepare(List<Item> &values, SELECT_LEX_UNIT *u)
|
||||
if (check_that_all_fields_are_given_values(thd, table, table_list))
|
||||
DBUG_RETURN(1);
|
||||
table->mark_columns_needed_for_insert();
|
||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -3320,24 +3440,19 @@ bool select_create::send_eof()
|
||||
|
||||
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
|
||||
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
mysql_unlock_tables(thd, thd->extra_lock);
|
||||
if (!table->s->tmp_table)
|
||||
if (thd->extra_lock)
|
||||
{
|
||||
if (close_thread_table(thd, &table))
|
||||
broadcast_refresh();
|
||||
mysql_unlock_tables(thd, thd->extra_lock);
|
||||
thd->extra_lock=0;
|
||||
}
|
||||
thd->extra_lock=0;
|
||||
table=0;
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
void select_create::abort()
|
||||
{
|
||||
DBUG_ENTER("select_create::abort");
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
|
||||
/*
|
||||
We roll back the statement, including truncating the transaction
|
||||
@ -3365,24 +3480,10 @@ void select_create::abort()
|
||||
{
|
||||
table->file->extra(HA_EXTRA_NO_IGNORE_DUP_KEY);
|
||||
table->file->extra(HA_EXTRA_WRITE_CANNOT_REPLACE);
|
||||
handlerton *table_type=table->s->db_type();
|
||||
if (!table->s->tmp_table)
|
||||
{
|
||||
ulong version= table->s->version;
|
||||
table->s->version= 0;
|
||||
hash_delete(&open_cache,(byte*) table);
|
||||
if (!create_info->table_existed)
|
||||
quick_rm_table(table_type, create_table->db,
|
||||
create_table->table_name, 0);
|
||||
/* Tell threads waiting for refresh that something has happened */
|
||||
if (version != refresh_version)
|
||||
broadcast_refresh();
|
||||
}
|
||||
else if (!create_info->table_existed)
|
||||
close_temporary_table(thd, table, 1, 1);
|
||||
if (!create_info->table_existed)
|
||||
drop_open_table(thd, table, create_table->db, create_table->table_name);
|
||||
table=0; // Safety
|
||||
}
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
@ -3394,8 +3495,8 @@ void select_create::abort()
|
||||
#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
|
||||
template class List_iterator_fast<List_item>;
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
template class I_List<delayed_insert>;
|
||||
template class I_List_iterator<delayed_insert>;
|
||||
template class I_List<Delayed_insert>;
|
||||
template class I_List_iterator<Delayed_insert>;
|
||||
template class I_List<delayed_row>;
|
||||
#endif /* EMBEDDED_LIBRARY */
|
||||
#endif /* HAVE_EXPLICIT_TEMPLATE_INSTANTIATION */
|
||||
|
Reference in New Issue
Block a user