1
0
mirror of https://github.com/MariaDB/server.git synced 2025-07-29 05:21:33 +03:00

Merged 5.1 with maria 5.1

This commit is contained in:
Michael Widenius
2008-10-10 18:28:41 +03:00
1924 changed files with 487105 additions and 167345 deletions

View File

@ -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
}
@ -1453,6 +1369,8 @@ bool close_thread_table(THD *thd, TABLE **table_ptr)
DBUG_ASSERT(!table->is_children_attached());
/* Free memory and reset for next loop */
free_field_buffers_larger_than(table,MAX_TDC_BLOB_SIZE);
table->file->ha_reset();
table->in_use=0;
if (unused_tables)
@ -3781,9 +3699,10 @@ void abort_locked_tables(THD *thd,const char *db, const char *table_name)
share->table_map_id is not ~0UL.
*/
static ulong last_table_id= ~0UL;
void assign_new_table_id(TABLE_SHARE *share)
{
static ulong last_table_id= ~0UL;
DBUG_ENTER("assign_new_table_id");
@ -3807,6 +3726,70 @@ 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);
}
DBUG_EXECUTE_IF("reprepare_each_statement",
if (thd->m_reprepare_observer &&
thd->stmt_arena->is_reprepared == FALSE)
{
thd->m_reprepare_observer->report_error(thd);
return TRUE;
});
return FALSE;
}
/*
Load a table definition from file and open unireg table
@ -3852,6 +3835,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;
@ -3869,6 +3858,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;
@ -4373,6 +4382,11 @@ bool fix_merge_after_open(TABLE_LIST *old_child_list, TABLE_LIST **old_last,
prelocking it won't do such precaching and will simply reuse table list
which is already built.
If any table has a trigger and start->trg_event_map is non-zero
the final lock will end up in thd->locked_tables, otherwise, the
lock will be placed in thd->lock. See also comments in
st_lex::set_trg_event_type_for_tables().
RETURN
0 - OK
-1 - error
@ -4465,8 +4479,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)++;
@ -4585,7 +4609,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags)
process its triggers since they never will be activated.
*/
if (!thd->prelocked_mode && !thd->lex->requires_prelocking() &&
tables->table->triggers &&
tables->trg_event_map && tables->table->triggers &&
tables->lock_type >= TL_WRITE_ALLOW_WRITE)
{
if (!query_tables_last_own)
@ -4614,6 +4638,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),
@ -4672,7 +4703,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));
@ -7583,9 +7618,34 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
continue;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
/* Ensure that we have access rights to all fields to be inserted. */
if (!((table && (table->grant.privilege & SELECT_ACL) ||
tables->view && (tables->grant.privilege & SELECT_ACL))) &&
/*
Ensure that we have access rights to all fields to be inserted. Under
some circumstances, this check may be skipped.
- If any_privileges is true, skip the check.
- If the SELECT privilege has been found as fulfilled already for both
the TABLE and TABLE_LIST objects (and both of these exist, of
course), the check is skipped.
- If the SELECT privilege has been found fulfilled for the TABLE object
and the TABLE_LIST represents a derived table other than a view (see
below), the check is skipped.
- If the TABLE_LIST object represents a view, we may skip checking if
the SELECT privilege has been found fulfilled for it, regardless of
the TABLE object.
- If there is no TABLE object, the test is skipped if either
* the TABLE_LIST does not represent a view, or
* the SELECT privilege has been found fulfilled.
A TABLE_LIST that is not a view may be a subquery, an
information_schema table, or a nested table reference. See the comment
for TABLE_LIST.
*/
if (!(table && !tables->view && (table->grant.privilege & SELECT_ACL) ||
tables->view && (tables->grant.privilege & SELECT_ACL)) &&
!any_privileges)
{
field_iterator.set(tables);
@ -7639,19 +7699,19 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name,
tables->is_natural_join);
DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
Item_field *fld= (Item_field*) item;
const char *field_table_name= field_iterator.table_name();
const char *field_table_name= field_iterator.get_table_name();
if (!tables->schema_table &&
!(fld->have_privileges=
(get_column_grant(thd, field_iterator.grant(),
field_iterator.db_name(),
field_iterator.get_db_name(),
field_table_name, fld->field_name) &
VIEW_ANY_ACL)))
{
my_error(ER_COLUMNACCESS_DENIED_ERROR, MYF(0), "ANY",
my_error(ER_TABLEACCESS_DENIED_ERROR, MYF(0), "ANY",
thd->security_ctx->priv_user,
thd->security_ctx->host_or_ip,
fld->field_name, field_table_name);
field_table_name);
DBUG_RETURN(TRUE);
}
}