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

BUG#5390 - problems with merge tables

Problem #1: INSERT...SELECT, Version for 5.1.
Extended the unique table check by a check of lock data.
Merge sub-tables cannot be detected by doing name checks only.
This commit is contained in:
ingo@mysql.com
2005-12-22 13:48:00 +01:00
parent 7b8fa1e3c6
commit a04c5adb0b
12 changed files with 216 additions and 39 deletions

View File

@ -428,6 +428,127 @@ MYSQL_LOCK *mysql_lock_merge(MYSQL_LOCK *a,MYSQL_LOCK *b)
}
/*
Find duplicate lock in tables.
SYNOPSIS
mysql_lock_have_duplicate()
thd The current thread.
needle The table to check for duplicate lock.
haystack The list of tables to search for the dup lock.
NOTE
This is mainly meant for MERGE tables in INSERT ... SELECT
situations. The 'real', underlying tables can be found only after
the table is opened. The easier way is to check this after the
tables are locked.
RETURN
1 A table from 'tables' matches a lock on 'table'.
0 No duplicate lock is present.
-1 Error.
*/
TABLE_LIST *mysql_lock_have_duplicate(THD *thd, TABLE_LIST *needle,
TABLE_LIST *haystack)
{
uint count;
uint dup_pos;
TABLE *write_lock_used; /* dummy */
TABLE **tables1;
TABLE **tables2;
TABLE **table_ptr;
TABLE_LIST *tlist_ptr;
MYSQL_LOCK *sql_lock1;
MYSQL_LOCK *sql_lock2;
THR_LOCK_DATA **lock_data1;
THR_LOCK_DATA **end_data1;
THR_LOCK_DATA **lock_data2;
THR_LOCK_DATA **end_data2;
THR_LOCK *lock1;
DBUG_ENTER("mysql_lock_have_duplicate");
/* Table may not be defined for derived or view tables. */
if (! needle->table)
DBUG_RETURN(NULL);
/* Get lock(s) for needle. */
tables1= &needle->table;
if (! (sql_lock1= get_lock_data(thd, tables1, 1, 1, &write_lock_used)))
goto err0;
/* Count real tables in list. */
count=0;
for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
count++;
/* Allocate a table array. */
if (! (tables2= (TABLE**) sql_alloc(sizeof(TABLE*) * count)))
goto err1;
table_ptr= tables2;
/* Assign table pointers. */
for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
*(table_ptr++)= tlist_ptr->table;
/* Get lock(s) for haystack. */
if (! (sql_lock2= get_lock_data(thd, tables2, count, 1, &write_lock_used)))
goto err1;
/* Initialize duplicate position to an impossible value. */
dup_pos= UINT_MAX;
/*
Find a duplicate lock.
In case of merge tables, sql_lock1 can have more than 1 lock.
*/
for (lock_data1= sql_lock1->locks,
end_data1= lock_data1 + sql_lock1->lock_count;
lock_data1 < end_data1;
lock_data1++)
{
lock1= (*lock_data1)->lock;
for (lock_data2= sql_lock2->locks,
end_data2= lock_data2 + sql_lock2->lock_count;
lock_data2 < end_data2;
lock_data2++)
{
if ((*lock_data2)->lock == lock1)
{
DBUG_PRINT("ingo", ("duplicate lock found"));
/* Change duplicate position to the real value. */
dup_pos= lock_data2 - sql_lock2->locks;
goto end;
}
}
}
end:
tlist_ptr= NULL; /* In case that no duplicate was found. */
if (dup_pos != UINT_MAX)
{
/* Duplicate found. Search the matching TABLE_LIST object. */
count= 0;
for (tlist_ptr = haystack; tlist_ptr; tlist_ptr= tlist_ptr->next_global)
{
if (! tlist_ptr->placeholder() && ! tlist_ptr->schema_table)
{
count+= tlist_ptr->table->file->lock_count();
if (count > dup_pos)
break;
}
}
}
my_free((gptr) sql_lock2, MYF(0));
my_free((gptr) sql_lock1, MYF(0));
DBUG_RETURN(tlist_ptr);
err1:
my_free((gptr) sql_lock1, MYF(0));
err0:
/* This non-null but special value indicates error, if caller cares. */
DBUG_RETURN(needle);
}
/* unlock a set of external */
static int unlock_external(THD *thd, TABLE **table,uint count)
@ -465,8 +586,8 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
MYSQL_LOCK *sql_lock;
THR_LOCK_DATA **locks;
TABLE **to;
DBUG_ENTER("get_lock_data");
DBUG_PRINT("info", ("count %d", count));
*write_lock_used=0;
for (i=tables=lock_count=0 ; i < count ; i++)