Commit c21728f8 authored by monty@narttu.mysql.fi's avatar monty@narttu.mysql.fi

Cleaner implementation if INSERT ... SELECT with same tables

Tests cleanup (put drop database first in tests)
parent b41cc923
......@@ -2592,14 +2592,11 @@ static void mysql_end_timer(ulong start_time,char *buff)
static const char* construct_prompt()
{
//erase the old prompt
if (!mysql_get_host_info(&mysql))
return processed_prompt.ptr();
processed_prompt.free();
//get the date struct
time_t lclock = time(NULL);
processed_prompt.free(); // Erase the old prompt
time_t lclock = time(NULL); // Get the date struct
struct tm *t = localtime(&lclock);
//parse thru the settings for the prompt
/* parse thru the settings for the prompt */
for (char *c = current_prompt; *c ; *c++)
{
if (*c != PROMPT_CHAR)
......@@ -2608,8 +2605,7 @@ static const char* construct_prompt()
{
switch (*++c) {
case '\0':
//stop it from going beyond if ends with %
c--;
c--; // stop it from going beyond if ends with %
break;
case 'c':
add_int_to_prompt(++prompt_counter);
......
......@@ -246,7 +246,6 @@ inline double ulonglong2double(ulonglong value)
#define HAVE_PERROR
#define HAVE_VFPRINT
#define HAVE_CHSIZE /* System has chsize() function */
#define HAVE_RENAME /* Have rename() as function */
#define HAVE_BINARY_STREAMS /* Have "b" flag in streams */
#define HAVE_LONG_JMP /* Have long jump function */
......
......@@ -893,8 +893,11 @@ typedef union {
double v;
long m[2];
} doubleget_union;
#define doubleget(V,M) { ((doubleget_union *)&V)->m[0] = *((long*) M); \
((doubleget_union *)&V)->m[1] = *(((long*) M)+1); }
#define doubleget(V,M) \
{ doubleget_union _tmp; \
_tmp.m[0] = *((long*)(M)); \
_tmp.m[1] = *(((long*) (M))+1); \
(V) = _tmp.v; }
#define doublestore(T,V) { *((long *) T) = ((doubleget_union *)&V)->m[0]; \
*(((long *) T)+1) = ((doubleget_union *)&V)->m[1]; }
#define float4get(V,M) { *((long *) &(V)) = *((long*) (M)); }
......
drop table if exists t1;
create table t1 (a varchar(10) not null);
insert into t1 values ("a"),("ab"),("abc");
select * from t1;
a
a
ab
abc
select a, left(a,1) as b from t1;
a b
a a
ab a
abc a
select a, left(a,1) as b from t1 group by a;
a b
a a
ab a
abc a
SELECT DISTINCT RIGHT(a,1) from t1;
RIGHT(a,1)
a
b
c
drop table t1;
drop table if exists t1;
drop table if exists t1;
drop table t1;
Unknown table 't1'
create table t1(n int);
......@@ -24,7 +23,6 @@ n
drop database if exists mysqltest;
create database mysqltest;
drop database mysqltest;
drop database if exists mysqltest;
flush tables with read lock;
create database mysqltest;
Got one of the listed errors
......
drop table if exists t1;
drop database if exists mysqltest;
create temporary table t1(n int not null primary key);
drop table if exists t2;
create table t2(n int);
......@@ -11,7 +12,6 @@ drop table t2;
Table 't2' was locked with a READ lock and can't be updated
drop table t2;
unlock tables;
drop database if exists mysqltest;
create database mysqltest;
create table mysqltest.t1(n int);
insert into mysqltest.t1 values (23);
......
drop table if exists test.t1,mysqltest.t1,mysqltest.t2;
drop database if exists mysqltest;
reset query cache;
flush status;
create database if not exists mysqltest;
......
drop table if exists t1,t2,t3;
drop database if exists mysqltest;
create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) type=innodb;
insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'), (2, 'Erik'), (3, 'Sasha'), (3, 'Jeremy'), (4, 'Matt');
select id, code, name from t1 order by id;
......
......@@ -566,4 +566,24 @@ a
5
5
5
insert into t1 select * from t1,t1;
Not unique table/alias: 't1'
drop table t1,t2;
create table t1 (a int not null primary key, b char(10));
create table t2 (a int not null, b char(10));
insert into t1 values (1,"t1:1"),(3,"t1:3");
insert into t2 values (2,"t2:2"), (3,"t2:3");
insert into t1 select * from t2;
Duplicate entry '3' for key 1
select * from t1;
a b
1 t1:1
3 t1:3
2 t2:2
replace into t1 select * from t2;
select * from t1;
a b
1 t1:1
3 t2:3
2 t2:2
drop table t1,t2;
......@@ -596,3 +596,15 @@ AND file_code = '0000000115' LIMIT 1;
table type possible_keys key key_len ref rows Extra
t2 const PRIMARY,files PRIMARY 33 const,const 1
DROP TABLE IF EXISTS t1, t2;
create table t1 (x int, y int, index xy(x, y));
create table t2 (x int, y int, index xy(x, y));
create table t3 (x int, y int, index xy(x, y)) type=merge union=(t1,t2);
insert into t1 values(1, 2);
insert into t2 values(1, 3);
select * from t3 where x = 1 and y < 5 order by y;
x y
1 2
1 3
select * from t3 where x = 1 and y < 5 order by y desc;
x y
drop table t1,t2,t3;
......@@ -3,6 +3,7 @@ flush query cache;
reset query cache;
flush status;
drop table if exists t1,t2,t3,t11,t21, mysqltest.t1;
drop database if exists mysqltest;
create table t1 (a int not null);
insert into t1 values (1),(2),(3);
select * from t1;
......@@ -357,7 +358,7 @@ show status like "Qcache_queries_in_cache";
Variable_name Value
Qcache_queries_in_cache 0
drop table t1,t2;
create database if not exists mysqltest;
create database mysqltest;
create table mysqltest.t1 (i int not null auto_increment, a int, primary key (i));
insert into mysqltest.t1 (a) values (1);
select * from mysqltest.t1 where i is null;
......
--default-character-set=cp1251 --new
# Test of charset cp1251
--disable_warnings
drop table if exists t1;
--enable_warnings
#
# Test problem with LEFT() (Bug #514)
#
create table t1 (a varchar(10) not null);
insert into t1 values ("a"),("ab"),("abc");
select * from t1;
select a, left(a,1) as b from t1;
select a, left(a,1) as b from t1 group by a;
SELECT DISTINCT RIGHT(a,1) from t1;
drop table t1;
drop table if exists t1;
drop table if exists t1;
--error 1051;
drop table t1;
create table t1(n int);
......@@ -26,7 +25,6 @@ create database mysqltest;
drop database mysqltest;
# test drop/create database and FLUSH TABLES WITH READ LOCK
drop database if exists mysqltest;
flush tables with read lock;
--error 1209,1223;
create database mysqltest;
......
......@@ -10,6 +10,8 @@ connect (con1,localhost,root,,);
connect (con2,localhost,root,,);
connection con1;
drop table if exists t1;
drop database if exists mysqltest;
create temporary table t1(n int not null primary key);
drop table if exists t2;
create table t2(n int);
......@@ -44,7 +46,6 @@ reap;
#test if drop database will wait until we release the global read lock
connection con1;
drop database if exists mysqltest;
create database mysqltest;
create table mysqltest.t1(n int);
insert into mysqltest.t1 values (23);
......@@ -66,4 +67,3 @@ connection con2;
insert into t1 values (345);
select * from t1;
drop table t1;
-- source include/have_query_cache.inc
drop table if exists test.t1,mysqltest.t1,mysqltest.t2;
drop database if exists mysqltest;
#
# Test grants with query cache
#
drop table if exists test.t1,mysqltest.t1,mysqltest.t2;
reset query cache;
flush status;
connect (root,localhost,root,,test,$MASTER_MYPORT,master.sock);
......
......@@ -5,6 +5,8 @@
#
drop table if exists t1,t2,t3;
drop database if exists mysqltest;
create table t1 (id int unsigned not null auto_increment, code tinyint unsigned not null, name char(20) not null, primary key (id), key (code), unique (name)) type=innodb;
insert into t1 (code, name) values (1, 'Tim'), (1, 'Monty'), (2, 'David'), (2, 'Erik'), (3, 'Sasha'), (3, 'Jeremy'), (4, 'Matt');
......
......@@ -85,6 +85,11 @@ let $VERSION=`select version()`;
show binlog events;
drop table t1, t2;
drop table if exists t1, t2;
#
# Test of insert ... select from same table
#
create table t1 (a int not null);
create table t2 (a int not null);
insert into t1 values (1);
......@@ -99,4 +104,21 @@ insert into t2 select * from t1 as t2;
select * from t1;
insert into t1 select t2.a from t1,t2;
select * from t1;
--error 1066
insert into t1 select * from t1,t1;
drop table t1,t2;
#
# test replace ... select
#
create table t1 (a int not null primary key, b char(10));
create table t2 (a int not null, b char(10));
insert into t1 values (1,"t1:1"),(3,"t1:3");
insert into t2 values (2,"t2:2"), (3,"t2:3");
--error 1062
insert into t1 select * from t2;
select * from t1;
replace into t1 select * from t2;
select * from t1;
drop table t1,t2;
......@@ -237,3 +237,16 @@ EXPLAIN SELECT * FROM t2 WHERE fileset_id = 2
AND file_code = '0000000115' LIMIT 1;
DROP TABLE IF EXISTS t1, t2;
#
# Test of ORDER BY DESC on key (Bug #515)
#
create table t1 (x int, y int, index xy(x, y));
create table t2 (x int, y int, index xy(x, y));
create table t3 (x int, y int, index xy(x, y)) type=merge union=(t1,t2);
insert into t1 values(1, 2);
insert into t2 values(1, 3);
select * from t3 where x = 1 and y < 5 order by y;
# Bug is that followng query returns empty set while it must be same as above
select * from t3 where x = 1 and y < 5 order by y desc;
drop table t1,t2,t3;
......@@ -11,6 +11,7 @@ flush query cache; # This crashed in some versions
reset query cache;
flush status;
drop table if exists t1,t2,t3,t11,t21, mysqltest.t1;
drop database if exists mysqltest;
#
# First simple test
......@@ -241,7 +242,7 @@ drop table t1,t2;
#
# noncachable ODBC work around (and prepare cache for drop database)
#
create database if not exists mysqltest;
create database mysqltest;
create table mysqltest.t1 (i int not null auto_increment, a int, primary key (i));
insert into mysqltest.t1 (a) values (1);
select * from mysqltest.t1 where i is null;
......
......@@ -3,10 +3,12 @@ disable_query_log;
show variables like "have_symlink";
enable_query_log;
drop table if exists t1,t2,t7,t8,t9;
drop database if exists mysqltest;
#
# First create little data to play with
#
drop table if exists t1,t2,t7,t8,t9;
create table t1 (a int not null auto_increment, b char(16) not null, primary key (a));
create table t2 (a int not null auto_increment, b char(16) not null, primary key (a));
insert into t1 (b) values ("test"),("test1"),("test2"),("test3");
......@@ -64,26 +66,25 @@ create table t1 (a int not null auto_increment, b char(16) not null, primary key
# Check that we cannot link over a table from another database.
drop database if exists test_mysqltest;
create database test_mysqltest;
create database mysqltest;
--error 1,1
create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="/this-dir-does-not-exist";
create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="/this-dir-does-not-exist";
--error 1103,1103
create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="not-hard-path";
create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="not-hard-path";
--error 1,1
eval create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="$MYSQL_TEST_DIR/var/run";
eval create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam index directory="$MYSQL_TEST_DIR/var/run";
--error 1,1
eval create table test_mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="$MYSQL_TEST_DIR/var/tmp";
eval create table mysqltest.t9 (a int not null auto_increment, b char(16) not null, primary key (a)) type=myisam data directory="$MYSQL_TEST_DIR/var/tmp";
enable_query_log;
# Check moving table t9 from default database to test_mysqltest;
# Check moving table t9 from default database to mysqltest;
# In this case the symlinks should be removed.
alter table t9 rename test_mysqltest.t9;
select count(*) from test_mysqltest.t9;
show create table test_mysqltest.t9;
drop database test_mysqltest;
alter table t9 rename mysqltest.t9;
select count(*) from mysqltest.t9;
show create table mysqltest.t9;
drop database mysqltest;
......@@ -253,6 +253,17 @@ typedef struct st_sql_list {
next= next_ptr;
*next=0;
}
inline void save_and_clear(struct st_sql_list *save)
{
*save= *this;
empty();
}
inline void push_front(struct st_sql_list *save)
{
*save->next= first; /* link current list last */
first= save->first;
elements+= save->elements;
}
} SQL_LIST;
......
......@@ -153,7 +153,7 @@ typedef struct st_lex
List<Item> *insert_list,field_list,value_list;
List<List_item> many_values;
List<set_var_base> var_list;
SQL_LIST proc_list, auxilliary_table_list;
SQL_LIST proc_list, auxilliary_table_list, save_list;
TYPELIB *interval;
create_field *last_field;
char* savepoint_name; // Transaction savepoint id
......
......@@ -15,12 +15,11 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
/* mysql standard open memoryallocator */
#ifdef __GNUC__
#pragma interface /* gcc class implementation */
#endif
/* mysql standard class memoryallocator */
class Sql_alloc
{
......@@ -38,14 +37,15 @@ class Sql_alloc
};
/*
** basic single linked list
** Used for item and item_buffs.
** All list ends with a pointer to the 'end_of_list' element, which
** data pointer is a null pointer and the next pointer points to itself.
** This makes it very fast to traverse lists as we don't have to
** test for a specialend condition for list that can't contain a null
** pointer.
Basic single linked list
Used for item and item_buffs.
All list ends with a pointer to the 'end_of_list' element, which
data pointer is a null pointer and the next pointer points to itself.
This makes it very fast to traverse lists as we don't have to
test for a specialend condition for list that can't contain a null
pointer.
*/
class list_node :public Sql_alloc
......@@ -65,9 +65,11 @@ class list_node :public Sql_alloc
friend class base_list_iterator;
};
extern list_node end_of_list;
class base_list :public Sql_alloc {
class base_list :public Sql_alloc
{
protected:
list_node *first,**last;
......@@ -243,6 +245,7 @@ template <class T> class List_iterator :public base_list_iterator
inline T** ref(void) { return (T**) base_list_iterator::ref(); }
};
template <class T> class List_iterator_fast :public base_list_iterator
{
protected:
......@@ -260,11 +263,12 @@ template <class T> class List_iterator_fast :public base_list_iterator
/*
** A simple intrusive list which automaticly removes element from list
** on delete (for THD element)
A simple intrusive list which automaticly removes element from list
on delete (for THD element)
*/
struct ilink {
struct ilink
{
struct ilink **prev,*next;
static void *operator new(size_t size)
{
......@@ -289,9 +293,11 @@ struct ilink {
virtual ~ilink() { unlink(); } /*lint -e1740 */
};
template <class T> class I_List_iterator;
class base_ilist {
class base_ilist
{
public:
struct ilink *first,last;
base_ilist() { first= &last; last.prev= &first; }
......@@ -339,7 +345,8 @@ class base_ilist_iterator
template <class T>
class I_List :private base_ilist {
class I_List :private base_ilist
{
public:
I_List() :base_ilist() {}
inline bool is_empty() { return base_ilist::is_empty(); }
......
......@@ -1972,6 +1972,11 @@ mysql_execute_command(void)
if (thd->select_limit < select_lex->select_limit)
thd->select_limit= HA_POS_ERROR; // No limit
if (check_dup(tables->db, tables->real_name, tables->next))
{
/* Using same table for INSERT and SELECT */
select_lex->options |= OPTION_BUFFER_RESULT;
}
{
/* TODO: Delete the following loop when locks is set by sql_yacc */
TABLE_LIST *table;
......@@ -2478,9 +2483,11 @@ mysql_execute_command(void)
res = mysql_ha_close(thd, tables);
break;
case SQLCOM_HA_READ:
/* there is no need to check for table permissions here, because
if a user has no permissions to read a table, he won't be
able to open it (with SQLCOM_HA_OPEN) in the first place. */
/*
There is no need to check for table permissions here, because
if a user has no permissions to read a table, he won't be
able to open it (with SQLCOM_HA_OPEN) in the first place.
*/
if (check_db_used(thd,tables))
goto error;
res = mysql_ha_read(thd, tables, lex->ha_read_mode, lex->backup_dir,
......@@ -2898,10 +2905,7 @@ void mysql_init_multi_delete(LEX *lex)
lex->sql_command = SQLCOM_DELETE_MULTI;
mysql_init_select(lex);
lex->select->select_limit=lex->thd->select_limit=HA_POS_ERROR;
lex->auxilliary_table_list=lex->select_lex.table_list;
lex->select->table_list.elements=0;
lex->select->table_list.first=0;
lex->select->table_list.next= (byte**) &(lex->select->table_list.first);
lex->select->table_list.save_and_clear(&lex->auxilliary_table_list);
}
......@@ -3386,22 +3390,10 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
tables ;
tables=tables->next)
{
if (ptr->db_length == tables->db_length && !memcmp(ptr->db, tables->db, ptr->db_length))
if (!strcmp(alias_str,tables->alias) && !strcmp(ptr->db, tables->db))
{
if ((thd->lex.sql_command & (SQLCOM_INSERT_SELECT | SQLCOM_REPLACE_SELECT))
&& (tables->lock_type & (TL_WRITE_CONCURRENT_INSERT |
TL_WRITE_LOW_PRIORITY | TL_WRITE_DELAYED |
TL_WRITE)))
{
if (ptr->real_name_length == tables->real_name_length &&
!memcmp(ptr->real_name, tables->real_name,ptr->real_name_length))
thd->lex.select->options |= OPTION_BUFFER_RESULT;
}
else if (!strcmp(alias_str,tables->alias))
{
net_printf(&thd->net,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
DBUG_RETURN(0); /* purecov: tested */
}
net_printf(&thd->net,ER_NONUNIQ_TABLE,alias_str); /* purecov: tested */
DBUG_RETURN(0); /* purecov: tested */
}
}
}
......
......@@ -824,13 +824,15 @@ create_select:
{
LEX *lex=Lex;
lex->lock_option= (using_update_log) ? TL_READ_NO_INSERT : TL_READ;
switch(lex->sql_command) {
case SQLCOM_INSERT: lex->sql_command=SQLCOM_INSERT_SELECT; break;
case SQLCOM_REPLACE: lex->sql_command=SQLCOM_REPLACE_SELECT; break;
}
if (lex->sql_command == SQLCOM_INSERT)
lex->sql_command= SQLCOM_INSERT_SELECT;
else if (lex->sql_command == SQLCOM_REPLACE)
lex->sql_command= SQLCOM_REPLACE_SELECT;
lex->select->table_list.save_and_clear(&lex->save_list);
mysql_init_select(lex);
}
select_options select_item_list opt_select_from
{ Lex->select->table_list.push_front(&Lex->save_list); }
;
opt_as:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment