1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-30 16:24:05 +03:00

Merge with 5.2.

no_error handling for select (used by INSERT ... SELECT) still needs to be fixed, but I will do that in a separate commit
This commit is contained in:
Michael Widenius
2011-12-11 11:34:44 +02:00
1166 changed files with 25635 additions and 15193 deletions

View File

@ -98,6 +98,13 @@ static TABLE_SHARE *oldest_unused_share, end_of_unused_share;
static pthread_mutex_t LOCK_table_share;
static bool table_def_inited= 0;
/**
Dummy TABLE instance which is used in reopen_tables() and reattach_merge()
functions to mark MERGE tables and their children with which there is some
kind of problem and which therefore we need to close.
*/
static TABLE bad_merge_marker;
static int open_unireg_entry(THD *thd, TABLE *entry, TABLE_LIST *table_list,
const char *alias,
char *cache_key, uint cache_key_length,
@ -786,6 +793,7 @@ void intern_close_table(TABLE *table)
delete table->triggers;
if (table->file) // Not true if name lock
VOID(closefrm(table, 1)); // close file
table->alias.free();
DBUG_VOID_RETURN;
}
@ -2303,7 +2311,12 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in)
if (thd->killed || !table)
DBUG_RETURN(TRUE);
orig_table= *table;
/*
make a copy. we may need to restore it later.
don't use orig_table=*table, because we need an exact replica,
not a C++ copy that may modify the data in the copy constructor.
*/
memcpy(&orig_table, table, sizeof(*table));
if (open_unireg_entry(thd, table, table_list, table_name,
table->s->table_cache_key.str,
@ -2316,7 +2329,8 @@ bool reopen_name_locked_table(THD* thd, TABLE_LIST* table_list, bool link_in)
properly release name-lock in this case we should restore this
object to its original state.
*/
*table= orig_table;
memcpy(table, &orig_table, sizeof(*table));
bzero(&orig_table, sizeof(orig_table)); // Ensure alias is not freed
DBUG_RETURN(TRUE);
}
@ -3257,47 +3271,66 @@ void close_data_files_and_morph_locks(THD *thd, const char *db,
}
/**
@brief Mark merge parent and children with bad_merge_marker
@param[in,out] parent the TABLE object of the parent
*/
static void mark_merge_parent_and_children_as_bad(TABLE *parent)
{
TABLE_LIST *child_l;
DBUG_ENTER("mark_merge_parent_and_children_as_bad");
parent->parent= &bad_merge_marker;
for (child_l= parent->child_l; ; child_l= child_l->next_global)
{
child_l->table->parent= &bad_merge_marker;
child_l->table= NULL;
if (&child_l->next_global == parent->child_last_l)
break;
}
DBUG_VOID_RETURN;
}
/**
Reattach MERGE children after reopen.
@param[in] thd thread context
@param[in,out] err_tables_p pointer to pointer of tables in error
@note If reattach failed for certain MERGE table, the table (and all
it's children) are marked with bad_merge_marker.
@return status
@retval FALSE OK, err_tables_p unchanged
@retval TRUE Error, err_tables_p contains table(s)
@retval FALSE OK
@retval TRUE Error
*/
static bool reattach_merge(THD *thd, TABLE **err_tables_p)
static bool reattach_merge(THD *thd)
{
TABLE *table;
TABLE *next;
TABLE **prv_p= &thd->open_tables;
bool error= FALSE;
DBUG_ENTER("reattach_merge");
for (table= thd->open_tables; table; table= next)
for (table= thd->open_tables; table; table= table->next)
{
next= table->next;
DBUG_PRINT("tcache", ("check table: '%s'.'%s' 0x%lx next: 0x%lx",
DBUG_PRINT("tcache", ("check table: '%s'.'%s' 0x%lx",
table->s->db.str, table->s->table_name.str,
(long) table, (long) next));
/* Reattach children for MERGE tables with "closed data files" only. */
if (table->child_l && !table->children_attached)
(long) table));
/*
Reattach children only for MERGE tables that had children or parent
with "closed data files" and were reopen. For extra safety skip MERGE
tables which we failed to reopen (should not happen with current code).
*/
if (table->child_l && table->parent != &bad_merge_marker &&
!table->children_attached)
{
DBUG_PRINT("tcache", ("MERGE parent, attach children"));
if(table->file->extra(HA_EXTRA_ATTACH_CHILDREN))
if (table->file->extra(HA_EXTRA_ATTACH_CHILDREN))
{
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias.c_ptr());
error= TRUE;
/* Remove table from open_tables. */
*prv_p= next;
if (next)
prv_p= &next->next;
/* Stack table on error list. */
table->next= *err_tables_p;
*err_tables_p= table;
continue;
mark_merge_parent_and_children_as_bad(table);
}
else
{
@ -3307,7 +3340,6 @@ static bool reattach_merge(THD *thd, TABLE **err_tables_p)
table->s->table_name.str, (long) table));
}
}
prv_p= &table->next;
}
DBUG_RETURN(error);
}
@ -3337,13 +3369,11 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old)
{
TABLE *table,*next,**prev;
TABLE **tables,**tables_ptr; // For locks
TABLE *err_tables= NULL;
bool error=0, not_used;
bool merge_table_found= FALSE;
const uint flags= MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN |
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK |
MYSQL_LOCK_IGNORE_FLUSH;
DBUG_ENTER("reopen_tables");
if (!thd->open_tables)
@ -3371,32 +3401,68 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old)
for (table=thd->open_tables; table ; table=next)
{
uint db_stat=table->db_stat;
TABLE *parent= table->child_l ? table : table->parent;
next=table->next;
DBUG_PRINT("tcache", ("open table: '%s'.'%s' 0x%lx "
"parent: 0x%lx db_stat: %u",
table->s->db.str, table->s->table_name.str,
(long) table, (long) table->parent, db_stat));
if (table->child_l && !db_stat)
/*
If we need to reopen child or parent table in a MERGE table, then
children in this MERGE table has to be already detached at this
point.
*/
DBUG_ASSERT(db_stat || !parent || !parent->children_attached);
/*
Thanks to the above assumption the below condition will guarantee that
merge_table_found is TRUE when we need to reopen child or parent table.
Note that it works even in situation when it is only a child and not a
parent that needs reopen (this can happen when get_locks == FALSE).
*/
if (table->child_l && !table->children_attached)
merge_table_found= TRUE;
if (!tables || (!db_stat && reopen_table(table)))
if (!tables)
{
my_error(ER_CANT_REOPEN_TABLE, MYF(0),
table->alias.ptr() ? table->alias.c_ptr() :
table->s->table_name.str);
/*
If we could not allocate 'tables', we may close open tables
here. If a MERGE table is affected, detach the children first.
It is not necessary to clear the child or parent table reference
of this table because the TABLE is freed. But we need to clear
the child or parent references of the other belonging tables so
that they cannot be moved into the unused_tables chain with
these pointers set.
If we could not allocate 'tables' we close ALL open tables here.
Before closing MERGE child or parent we need to detach children
and/or clear references in/to them.
*/
unlink_open_table(thd, table, 0);
/* Restart loop */
prev= &thd->open_tables;
next= *prev;
error=1;
if (parent)
detach_merge_children(table, TRUE);
}
else if (table->parent == &bad_merge_marker)
{
/*
This is either a child or a parent of a MERGE table for which
we already decided that we are unable to reopen it. Close it.
Reset parent reference, it may be used while freeing the table.
*/
table->parent= NULL;
}
else if (!db_stat && reopen_table(table))
{
/*
If we fail to reopen a child or a parent in a MERGE table and the
MERGE table is affected for the first time, mark all relevant tables
invalid. Otherwise handle it as usual.
All in all we must end up with:
- child tables are detached from parent. This was done earlier,
but child<->parent references were kept valid for reopen.
- parent is not in the to-be-locked tables
- all child tables and parent are not in the THD::open_tables.
- all child tables and parent are not in the open_cache.
Please note that below we do additional pass through THD::open_tables
list to achieve the last three points.
*/
if (parent)
{
mark_merge_parent_and_children_as_bad(parent);
table->parent= NULL;
}
}
else
{
@ -3412,21 +3478,59 @@ bool reopen_tables(THD *thd, bool get_locks, bool mark_share_as_old)
table->s->version=0;
table->open_placeholder= 0;
}
continue;
}
my_error(ER_CANT_REOPEN_TABLE, MYF(0), table->alias.c_ptr());
unlink_open_table(thd, table, 0);
/* Restart loop, as one of the used tables may now be closed */
prev= &thd->open_tables;
next= *prev;
error=1;
}
*prev=0;
/*
When all tables are open again, we can re-attach MERGE children to
their parents. All TABLE objects are still present.
their parents.
If there was an error while reopening a child or a parent of a MERGE
table, or while reattaching child tables to their parents, some tables
may have been kept open but marked for close with bad_merge_marker.
Close these tables now.
*/
DBUG_PRINT("tcache", ("re-attaching MERGE tables: %d", merge_table_found));
if (!error && merge_table_found && reattach_merge(thd, &err_tables))
if (tables && merge_table_found && (error|= reattach_merge(thd)))
{
while (err_tables)
prev= &thd->open_tables;
for (table= thd->open_tables; table; table= next)
{
VOID(hash_delete(&open_cache, (uchar*) err_tables));
err_tables= err_tables->next;
next= table->next;
if (table->parent == &bad_merge_marker)
{
/* Remove merge parent from to-be-locked tables array. */
if (get_locks && table->child_l)
{
TABLE **t;
for (t= tables; t < tables_ptr; t++)
{
if (*t == table)
{
tables_ptr--;
memmove(t, t + 1, (tables_ptr - t) * sizeof(TABLE *));
break;
}
}
}
/* Reset parent reference, it may be used while freeing the table. */
table->parent= NULL;
/* Free table. */
VOID(hash_delete(&open_cache, (uchar *) table));
}
else
{
*prev= table;
prev= &table->next;
}
}
*prev= 0;
}
DBUG_PRINT("tcache", ("open tables to lock: %u",
(uint) (tables_ptr - tables)));
@ -3579,8 +3683,7 @@ bool table_is_used(TABLE *table, bool wait_for_name_lock)
char *key= table->s->table_cache_key.str;
uint key_length= table->s->table_cache_key.length;
DBUG_PRINT("loop", ("table_name: %s",
table->alias.ptr() ? table->alias.c_ptr() : ""));
DBUG_PRINT("loop", ("table_name: %s.%s", key, strend(key)+1));
HASH_SEARCH_STATE state;
for (TABLE *search= (TABLE*) hash_first(&open_cache, (uchar*) key,
key_length, &state);
@ -4066,7 +4169,7 @@ retry:
{
/* Give right error message */
thd->clear_error();
my_error(ER_NOT_KEYFILE, MYF(0), share->table_name.str, my_errno);
my_error(ER_NOT_KEYFILE, MYF(0), share->table_name.str);
sql_print_error("Couldn't repair table: %s.%s", share->db.str,
share->table_name.str);
if (entry->file)
@ -4627,9 +4730,6 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
*/
for (tables= *start; tables ;tables= tables->next_global)
{
DBUG_PRINT("tcache", ("opening table: '%s'.'%s' item: 0x%lx",
tables->db, tables->table_name, (long) tables));
safe_to_ignore_table= FALSE;
/*
@ -4642,8 +4742,11 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
{
if (tables->view)
goto process_view_routines;
DBUG_PRINT("tcache", ("ignoring placeholder for derived table"));
continue;
}
DBUG_PRINT("tcache", ("opening table: '%s'.'%s' item: 0x%lx",
tables->db, tables->table_name, (long) tables));
/*
If this TABLE_LIST object is a placeholder for an information_schema
table, create a temporary table to represent the information_schema
@ -7698,7 +7801,7 @@ bool setup_fields(THD *thd, Item **ref_pointer_array,
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
sum_func_list)
item->split_sum_func(thd, ref_pointer_array, *sum_func_list);
thd->used_tables|= item->used_tables();
thd->lex->used_tables|= item->used_tables();
thd->lex->current_select->cur_pos_in_select_list++;
}
thd->lex->current_select->is_item_list_lookup= save_is_item_list_lookup;
@ -7844,7 +7947,7 @@ bool setup_tables(THD *thd, Name_resolution_context *context,
}
if (tablenr > MAX_TABLES)
{
my_error(ER_TOO_MANY_TABLES,MYF(0),MAX_TABLES);
my_error(ER_TOO_MANY_TABLES,MYF(0), (int) MAX_TABLES);
DBUG_RETURN(1);
}
}
@ -8118,7 +8221,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
views and natural joins this update is performed inside the loop below.
*/
if (table)
thd->used_tables|= table->map;
thd->lex->used_tables|= table->map;
/*
Initialize a generic field iterator for the current table reference.
@ -8209,7 +8312,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
field_table= nj_col->table_ref->table;
if (field_table)
{
thd->used_tables|= field_table->map;
thd->lex->used_tables|= field_table->map;
field_table->covering_keys.intersect(field->part_of_key);
field_table->merge_keys.merge(field->part_of_key);
field_table->used_fields++;
@ -8217,7 +8320,7 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
}
}
else
thd->used_tables|= item->used_tables();
thd->lex->used_tables|= item->used_tables();
thd->lex->current_select->cur_pos_in_select_list++;
}
/*