mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
Merge bk-internal.mysql.com:/home/bk/mysql-5.1
into bodhi.(none):/opt/local/work/mysql-5.1-27430
This commit is contained in:
200
sql/sql_base.cc
200
sql/sql_base.cc
@ -345,26 +345,9 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
|
||||
|
||||
if (!(share= alloc_table_share(table_list, key, key_length)))
|
||||
{
|
||||
#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
#endif
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3
|
||||
// We need a write lock to be able to add a new entry
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
/* Check that another thread didn't insert the same table in between */
|
||||
if ((old_share= hash_search(&table_def_cache, (uchar*) key, key_length)))
|
||||
{
|
||||
(void) pthread_mutex_lock(&share->mutex);
|
||||
free_table_share(share);
|
||||
share= old_share;
|
||||
goto found;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
Lock mutex to be able to read table definition from file without
|
||||
conflicts
|
||||
@ -388,29 +371,11 @@ TABLE_SHARE *get_table_share(THD *thd, TABLE_LIST *table_list, char *key,
|
||||
|
||||
if (my_hash_insert(&table_def_cache, (uchar*) share))
|
||||
{
|
||||
#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
(void) pthread_mutex_unlock(&share->mutex);
|
||||
#endif
|
||||
free_table_share(share);
|
||||
DBUG_RETURN(0); // return error
|
||||
}
|
||||
#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
#endif
|
||||
if (open_table_def(thd, share, db_flags))
|
||||
{
|
||||
#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3
|
||||
/*
|
||||
No such table or wrong table definition file
|
||||
Lock first the table cache and then the mutex.
|
||||
This will ensure that no other thread is using the share
|
||||
structure.
|
||||
*/
|
||||
(void) pthread_mutex_unlock(&share->mutex);
|
||||
(void) pthread_mutex_lock(&LOCK_open);
|
||||
(void) pthread_mutex_lock(&share->mutex);
|
||||
#endif
|
||||
*error= share->error;
|
||||
(void) hash_delete(&table_def_cache, (uchar*) share);
|
||||
DBUG_RETURN(0);
|
||||
@ -429,9 +394,6 @@ found:
|
||||
|
||||
/* We must do a lock to ensure that the structure is initialized */
|
||||
(void) pthread_mutex_lock(&share->mutex);
|
||||
#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
#endif
|
||||
if (share->error)
|
||||
{
|
||||
/* Table definition contained an error */
|
||||
@ -618,52 +580,6 @@ void release_table_share(TABLE_SHARE *share, enum release_type type)
|
||||
}
|
||||
pthread_mutex_unlock(&share->mutex);
|
||||
DBUG_VOID_RETURN;
|
||||
|
||||
|
||||
#ifdef WAITING_FOR_TABLE_DEF_CACHE_STAGE_3
|
||||
if (to_be_deleted)
|
||||
{
|
||||
/*
|
||||
We must try again with new locks as we must get LOCK_open
|
||||
before share->mutex
|
||||
*/
|
||||
pthread_mutex_unlock(&share->mutex);
|
||||
pthread_mutex_lock(&LOCK_open);
|
||||
pthread_mutex_lock(&share->mutex);
|
||||
if (!share->ref_count)
|
||||
{ // No one is using this now
|
||||
TABLE_SHARE *name_lock;
|
||||
if (share->replace_with_name_lock && (name_lock=get_name_lock(share)))
|
||||
{
|
||||
/*
|
||||
This code is execured when someone does FLUSH TABLES while on has
|
||||
locked tables.
|
||||
*/
|
||||
(void) hash_search(&def_cache,(uchar*) key,key_length);
|
||||
hash_replace(&def_cache, def_cache.current_record,(uchar*) name_lock);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remove table definition */
|
||||
hash_delete(&def_cache,(uchar*) share);
|
||||
}
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
free_table_share(share);
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_unlock(&LOCK_open);
|
||||
if (type == RELEASE_WAIT_FOR_DROP)
|
||||
wait_for_table(share, "Waiting for close");
|
||||
else
|
||||
pthread_mutex_unlock(&share->mutex);
|
||||
}
|
||||
}
|
||||
else if (type == RELEASE_WAIT_FOR_DROP)
|
||||
wait_for_table(share, "Waiting for close");
|
||||
else
|
||||
pthread_mutex_unlock(&share->mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@ -3801,6 +3717,73 @@ void assign_new_table_id(TABLE_SHARE *share)
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Compare metadata versions of an element obtained from the table
|
||||
definition cache and its corresponding node in the parse tree.
|
||||
|
||||
@details If the new and the old values mismatch, invoke
|
||||
Metadata_version_observer.
|
||||
At prepared statement prepare, all TABLE_LIST version values are
|
||||
NULL and we always have a mismatch. But there is no observer set
|
||||
in THD, and therefore no error is reported. Instead, we update
|
||||
the value in the parse tree, effectively recording the original
|
||||
version.
|
||||
At prepared statement execute, an observer may be installed. If
|
||||
there is a version mismatch, we push an error and return TRUE.
|
||||
|
||||
For conventional execution (no prepared statements), the
|
||||
observer is never installed.
|
||||
|
||||
@sa Execute_observer
|
||||
@sa check_prepared_statement() to see cases when an observer is installed
|
||||
@sa TABLE_LIST::is_table_ref_id_equal()
|
||||
@sa TABLE_SHARE::get_table_ref_id()
|
||||
|
||||
@param[in] thd used to report errors
|
||||
@param[in,out] tables TABLE_LIST instance created by the parser
|
||||
Metadata version information in this object
|
||||
is updated upon success.
|
||||
@param[in] table_share an element from the table definition cache
|
||||
|
||||
@retval TRUE an error, which has been reported
|
||||
@retval FALSE success, version in TABLE_LIST has been updated
|
||||
*/
|
||||
|
||||
bool
|
||||
check_and_update_table_version(THD *thd,
|
||||
TABLE_LIST *tables, TABLE_SHARE *table_share)
|
||||
{
|
||||
if (! tables->is_table_ref_id_equal(table_share))
|
||||
{
|
||||
if (thd->m_reprepare_observer &&
|
||||
thd->m_reprepare_observer->report_error(thd))
|
||||
{
|
||||
/*
|
||||
Version of the table share is different from the
|
||||
previous execution of the prepared statement, and it is
|
||||
unacceptable for this SQLCOM. Error has been reported.
|
||||
*/
|
||||
DBUG_ASSERT(thd->is_error());
|
||||
return TRUE;
|
||||
}
|
||||
/* Always maintain the latest version and type */
|
||||
tables->set_table_ref_id(table_share);
|
||||
}
|
||||
|
||||
#ifndef DBUG_OFF
|
||||
/* Spuriously reprepare each statement. */
|
||||
if (_db_strict_keyword_("reprepare_each_statement") &&
|
||||
thd->m_reprepare_observer && thd->stmt_arena->is_reprepared == FALSE)
|
||||
{
|
||||
thd->m_reprepare_observer->report_error(thd);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/*
|
||||
Load a table definition from file and open unireg table
|
||||
|
||||
@ -3846,6 +3829,12 @@ retry:
|
||||
|
||||
if (share->is_view)
|
||||
{
|
||||
/*
|
||||
This table is a view. Validate its metadata version: in particular,
|
||||
that it was a view when the statement was prepared.
|
||||
*/
|
||||
if (check_and_update_table_version(thd, table_list, share))
|
||||
goto err;
|
||||
if (table_list->i_s_requested_object & OPEN_TABLE_ONLY)
|
||||
goto err;
|
||||
|
||||
@ -3863,6 +3852,26 @@ retry:
|
||||
release_table_share(share, RELEASE_NORMAL);
|
||||
DBUG_RETURN((flags & OPEN_VIEW_NO_PARSE)? -1 : 0);
|
||||
}
|
||||
else if (table_list->view)
|
||||
{
|
||||
/*
|
||||
We're trying to open a table for what was a view.
|
||||
This can only happen during (re-)execution.
|
||||
At prepared statement prepare the view has been opened and
|
||||
merged into the statement parse tree. After that, someone
|
||||
performed a DDL and replaced the view with a base table.
|
||||
Don't try to open the table inside a prepared statement,
|
||||
invalidate it instead.
|
||||
|
||||
Note, the assert below is known to fail inside stored
|
||||
procedures (Bug#27011).
|
||||
*/
|
||||
DBUG_ASSERT(thd->m_reprepare_observer);
|
||||
check_and_update_table_version(thd, table_list, share);
|
||||
/* Always an error. */
|
||||
DBUG_ASSERT(thd->is_error());
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (table_list->i_s_requested_object & OPEN_VIEW_ONLY)
|
||||
goto err;
|
||||
@ -4464,8 +4473,18 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
||||
*/
|
||||
if (tables->schema_table)
|
||||
{
|
||||
if (!mysql_schema_table(thd, thd->lex, tables))
|
||||
/*
|
||||
If this information_schema table is merged into a mergeable
|
||||
view, ignore it for now -- it will be filled when its respective
|
||||
TABLE_LIST is processed. This code works only during re-execution.
|
||||
*/
|
||||
if (tables->view)
|
||||
goto process_view_routines;
|
||||
if (!mysql_schema_table(thd, thd->lex, tables) &&
|
||||
!check_and_update_table_version(thd, tables, tables->table->s))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
(*counter)++;
|
||||
@ -4613,6 +4632,13 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
|
||||
}
|
||||
tables->table->grant= tables->grant;
|
||||
|
||||
/* Check and update metadata version of a base table. */
|
||||
if (check_and_update_table_version(thd, tables, tables->table->s))
|
||||
{
|
||||
result= -1;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Attach MERGE children if not locked already. */
|
||||
DBUG_PRINT("tcache", ("is parent: %d is child: %d",
|
||||
test(tables->table->child_l),
|
||||
@ -4671,7 +4697,11 @@ process_view_routines:
|
||||
error happens on a MERGE child, clear the parents TABLE reference.
|
||||
*/
|
||||
if (tables->parent_l)
|
||||
{
|
||||
if (tables->parent_l->next_global == tables->parent_l->table->child_l)
|
||||
tables->parent_l->next_global= *tables->parent_l->table->child_last_l;
|
||||
tables->parent_l->table= NULL;
|
||||
}
|
||||
tables->table= NULL;
|
||||
}
|
||||
DBUG_PRINT("tcache", ("returning: %d", result));
|
||||
|
Reference in New Issue
Block a user