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:
223
sql/sql_base.cc
223
sql/sql_base.cc
@ -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++;
|
||||
}
|
||||
/*
|
||||
|
Reference in New Issue
Block a user