Commit f6cac54b authored by unknown's avatar unknown
Browse files

BUG#5390 - problems with merge tables

Problem #1: INSERT...SELECT, Version for 4.1.
INSERT ... SELECT with the same table on both sides (hidden
below a MERGE table) does now work by buffering the select result.
The duplicate detection works now after open_and_lock_tables() 
on the locks.
I did not find a test case that failed without the change in
sql_update.cc. I made the change anyway as it should in theory
fix a possible MERGE table problem with multi-table update.


libmysqld/ha_blackhole.cc:
  BUG#5390 - problems with merge tables
  No idea, how the symlink change made it into my patch.
mysql-test/r/create.result:
  BUG#5390 - problems with merge tables
  Removed a duplicate test.
mysql-test/r/merge.result:
  BUG#5390 - problems with merge tables
  Problem #1: INSERT...SELECT, Version for 4.1.
  Added test results.
mysql-test/t/create.test:
  BUG#5390 - problems with merge tables
  Removed a duplicate test.
mysql-test/t/merge.test:
  BUG#5390 - problems with merge tables
  Problem #1: INSERT...SELECT, Version for 4.1.
  Added tests.
sql/lock.cc:
  BUG#5390 - problems with merge tables
  Problem #1: INSERT...SELECT, Version for 4.1.
  Added a new function to find a duplicate lock in a list of tables.
sql/mysql_priv.h:
  BUG#5390 - problems with merge tables
  Problem #1: INSERT...SELECT, Version for 4.1.
  Added a declaration for the new function.
sql/sql_parse.cc:
  BUG#5390 - problems with merge tables
  Problem #1: INSERT...SELECT, Version for 4.1.
  Changed the duplicate tables detection for INSERT ... SELECT
  to use the new function, which does also work for MERGE tables.
sql/sql_update.cc:
  BUG#5390 - problems with merge tables
  Problem #1: INSERT...SELECT, Version for 4.1.
  Changed the duplicate tables detection for UPDATE
  to use the new function, which does also work for MERGE tables.
parent 966ab524
Loading
Loading
Loading
Loading
+0 −15
Original line number Diff line number Diff line
@@ -247,21 +247,6 @@ select * from t1;
0	1	2
0	0	1
drop table t1;
create table t1 select 1,2,3;
create table if not exists t1 select 1,2;
Warnings:
Note	1050	Table 't1' already exists
create table if not exists t1 select 1,2,3,4;
ERROR 21S01: Column count doesn't match value count at row 1
create table if not exists t1 select 1;
Warnings:
Note	1050	Table 't1' already exists
select * from t1;
1	2	3
1	2	3
0	1	2
0	0	1
drop table t1;
create table t1 (a int not null, b int, primary key (a));
insert into t1 values (1,1);
create table if not exists t1 select 2;
+49 −0
Original line number Diff line number Diff line
@@ -717,3 +717,52 @@ SELECT b FROM t2;
b
3
DROP TABLE t1, t2;
create table t1(a int);
create table t2(a int);
insert into t1 values (1);
insert into t2 values (2);
create table t3 (a int) engine=merge union=(t1, t2) insert_method=first;
select * from t3;
a
1
2
insert t2 select * from t2;
select * from t2;
a
2
2
insert t3 select * from t1;
select * from t3;
a
1
1
2
2
insert t1 select * from t3;
select * from t1;
a
1
1
1
1
2
2
select * from t2;
a
2
2
select * from t3;
a
1
1
1
1
2
2
2
2
check table t1, t2;
Table	Op	Msg_type	Msg_text
test.t1	check	status	OK
test.t2	check	status	OK
drop table t1, t2, t3;
+0 −7
Original line number Diff line number Diff line
@@ -200,13 +200,6 @@ drop table t1;
# bug #1434
#

create table t1 select 1,2,3;
create table if not exists t1 select 1,2;
--error 1136
create table if not exists t1 select 1,2,3,4;
create table if not exists t1 select 1;
select * from t1;
drop table t1;
create table t1 select 1,2,3;
create table if not exists t1 select 1,2;
--error 1136
+26 −0
Original line number Diff line number Diff line
@@ -350,4 +350,30 @@ INSERT INTO t2 (b) VALUES (1) ON DUPLICATE KEY UPDATE b=3;
SELECT b FROM t2;
DROP TABLE t1, t2;


#
# BUG#5390 - problems with merge tables
# Problem #1: INSERT...SELECT
#
#drop table if exists t1, t2, t3;
create table t1(a int);
create table t2(a int);
insert into t1 values (1);
insert into t2 values (2);
create table t3 (a int) engine=merge union=(t1, t2) insert_method=first;
select * from t3;
#
insert t2 select * from t2;
select * from t2;
#
insert t3 select * from t1;
select * from t3;
#
insert t1 select * from t3;
select * from t1;
select * from t2;
select * from t3;
check table t1, t2;
drop table t1, t2, t3;

# End of 4.1 tests
+86 −3
Original line number Diff line number Diff line
@@ -394,6 +394,88 @@ 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.
    table                       The table to check for duplicate lock.
    tables                      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.
*/

int mysql_lock_have_duplicate(THD *thd, TABLE *table, TABLE_LIST *tables)
{
  uint                  count;
  MYSQL_LOCK            *sql_lock1;
  MYSQL_LOCK            *sql_lock2;
  TABLE                 **tables1= &table;
  TABLE                 **tables2;
  TABLE                 **table_ptr;
  TABLE_LIST            *tablist2;
  TABLE                 *write_lock_used;
  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");

  if (! (sql_lock1= get_lock_data(thd, tables1, 1, 1, &write_lock_used)))
    goto err0;

  count=0;
  for (tablist2 = tables; tablist2; tablist2= tablist2->next)
    count++;
  if (! (tables2= (TABLE**) sql_alloc(sizeof(TABLE*) * count)))
    goto err1;
  table_ptr= tables2;
  for (tablist2 = tables; tablist2; tablist2= tablist2->next)
    *(table_ptr++)= tablist2->table;
  if (! (sql_lock2= get_lock_data(thd, tables2, count, 1, &write_lock_used)))
    goto err1;

  count= 1;
  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)
        goto end;
    }
  }
  count= 0;

 end:
  my_free((gptr) sql_lock2, MYF(0));
  my_free((gptr) sql_lock1, MYF(0));
  DBUG_RETURN(count);

 err1:
  my_free((gptr) sql_lock1, MYF(0));
 err0:
  DBUG_RETURN(-1);
}


	/* unlock a set of external */

static int unlock_external(THD *thd, TABLE **table,uint count)
@@ -430,6 +512,7 @@ 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");

  *write_lock_used=0;
  for (i=tables=lock_count=0 ; i < count ; i++)
@@ -445,7 +528,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
	my_malloc(sizeof(*sql_lock)+
		  sizeof(THR_LOCK_DATA*)*tables+sizeof(table_ptr)*lock_count,
		  MYF(0))))
    return 0;
    DBUG_RETURN(0);
  locks=sql_lock->locks=(THR_LOCK_DATA**) (sql_lock+1);
  to=sql_lock->table=(TABLE**) (locks+tables);
  sql_lock->table_count=lock_count;
@@ -465,7 +548,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
      {
	my_error(ER_OPEN_AS_READONLY,MYF(0),table->table_name);
	my_free((gptr) sql_lock,MYF(0));
	return 0;
	DBUG_RETURN(0);
      }
    }
    THR_LOCK_DATA **org_locks = locks;
@@ -475,7 +558,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
      for ( ; org_locks != locks ; org_locks++)
	(*org_locks)->debug_print_param= (void *) table;
  }
  return sql_lock;
  DBUG_RETURN(sql_lock);
}


Loading