Fix UNION
New faster list iterators Change list code to be simpler and faster Optimize count(distinct) New error messages for UNION Make create_tmp_table more general to be usable by UNION Docs/manual.texi: Changelog include/mysqld_error.h: Add new error messages needed for UNION mysql-test/r/union.result: New tests for UNION mysql-test/t/analyse.test: Add missing drop table mysql-test/t/union.test: new tests for UNION sql/Makefile.am: Change name of sql_unions.cc to sql_union.cc sql/item.cc: Use List_iterator_fast sql/item_cmpfunc.cc: Use List_iterator_fast sql/item_func.cc: Use List_iterator_fast sql/item_sum.cc: Use List_iterator_fast Optimize count(distinct) Cleanup of indentation and comments sql/item_sum.h: Optimize count(distinct) sql/key.cc: Use List_iterator_fast sql/mysql_priv.h: Add new option bits sql/opt_sum.cc: Use List_iterator_fast sql/share/Makefile.am: Add 'fix_errors' label sql/share/czech/errmsg.txt: Add new error messages needed for UNION sql/share/danish/errmsg.txt: Add new error messages needed for UNION sql/share/dutch/errmsg.txt: Add new error messages needed for UNION sql/share/english/errmsg.txt: Add new error messages needed for UNION sql/share/estonian/errmsg.txt: Add new error messages needed for UNION sql/share/french/errmsg.txt: Add new error messages needed for UNION sql/share/german/errmsg.txt: Add new error messages needed for UNION sql/share/greek/errmsg.txt: Add new error messages needed for UNION sql/share/hungarian/errmsg.txt: Add new error messages needed for UNION sql/share/italian/errmsg.txt: Add new error messages needed for UNION sql/share/japanese/errmsg.txt: Add new error messages needed for UNION sql/share/korean/errmsg.txt: Add new error messages needed for UNION sql/share/norwegian-ny/errmsg.txt: Add new error messages needed for UNION sql/share/norwegian/errmsg.txt: Add new error messages needed for UNION sql/share/polish/errmsg.txt: Add new error messages needed for UNION sql/share/portuguese/errmsg.txt: Add new error messages needed for UNION sql/share/romanian/errmsg.txt: Add new error messages needed for UNION sql/share/russian/errmsg.txt: Add new error messages needed for UNION sql/share/slovak/errmsg.txt: Add new error messages needed for UNION sql/share/spanish/errmsg.txt: Add new error messages needed for UNION sql/share/swedish/errmsg.txt: Add new error messages needed for UNION sql/sql_analyse.cc: Use List_iterator_fast sql/sql_base.cc: Use List_iterator_fast Add new argument to setup_fields sql/sql_class.cc: Use List_iterator_fast sql/sql_class.h: Create new class for UNION sql/sql_handler.cc: Use List_iterator_fast sql/sql_insert.cc: Use List_iterator_fast sql/sql_lex.h: Cleanup sql/sql_list.cc: Faster iteration of lists sql/sql_list.h: Faster iterations of lists sql/sql_load.cc: Use List_iterator_fast sql/sql_parse.cc: Fix UNION code sql/sql_select.cc: Use List_iterator_fast Make create_tmp_table more general to be usable by UNION sql/sql_select.h: Changes to speed up copy_fields() sql/sql_show.cc: Use List_iterator_fast sql/sql_table.cc: Use List_iterator_fast sql/sql_union.cc: Fix UNION code sql/sql_update.cc: Use List_iterator_fast sql/sql_yacc.yy: Fix UNION code
This commit is contained in:
parent
7c1e275715
commit
329e5f2f35
@ -45712,6 +45712,10 @@ Our TODO section contains what we plan to have in 4.0. @xref{TODO MySQL 4.0}.
|
||||
|
||||
@itemize @bullet
|
||||
@item
|
||||
Speed up all internal list handling.
|
||||
@item
|
||||
Added support for @code{UNION}.
|
||||
@item
|
||||
Allow ANSI SQL syntax @code{X'hexadecimal-number'}
|
||||
@item
|
||||
Tree-like cache to speed up bulk inserts and
|
||||
|
@ -213,4 +213,6 @@
|
||||
#define ER_CONNECT_TO_MASTER 1210
|
||||
#define ER_QUERY_ON_MASTER 1211
|
||||
#define ER_ERROR_WHEN_EXECUTING_COMMAND 1212
|
||||
#define ER_ERROR_MESSAGES 213
|
||||
#define ER_WRONG_USAGE 1213
|
||||
#define ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT 1214
|
||||
#define ER_ERROR_MESSAGES 215
|
||||
|
60
mysql-test/r/union.result
Normal file
60
mysql-test/r/union.result
Normal file
@ -0,0 +1,60 @@
|
||||
a b
|
||||
1 a
|
||||
2 b
|
||||
3 c
|
||||
4 d
|
||||
5 f
|
||||
6 e
|
||||
a b
|
||||
1 a
|
||||
2 b
|
||||
3 c
|
||||
3 c
|
||||
3 c
|
||||
4 d
|
||||
5 f
|
||||
6 e
|
||||
a b
|
||||
1 a
|
||||
2 b
|
||||
3 c
|
||||
3 c
|
||||
3 c
|
||||
4 d
|
||||
6 e
|
||||
5 f
|
||||
a b
|
||||
1 a
|
||||
2 b
|
||||
3 c
|
||||
3 c
|
||||
3 c
|
||||
4 d
|
||||
5 f
|
||||
6 e
|
||||
7 g
|
||||
0 #
|
||||
0 #
|
||||
1 a
|
||||
2 b
|
||||
3 c
|
||||
3 c
|
||||
3 c
|
||||
4 d
|
||||
5 f
|
||||
6 e
|
||||
7 g
|
||||
a b
|
||||
1 a
|
||||
2 b
|
||||
3 c
|
||||
t1 b count(*)
|
||||
t1 a 1
|
||||
t1 b 1
|
||||
t1 c 2
|
||||
t2 c 1
|
||||
t2 d 1
|
||||
t2 e 1
|
||||
t2 f 1
|
||||
table type possible_keys key key_len ref rows Extra
|
||||
t2 ALL NULL NULL NULL NULL 4
|
@ -1,15 +0,0 @@
|
||||
a b
|
||||
1 a
|
||||
2 b
|
||||
3 c
|
||||
4 d
|
||||
5 e
|
||||
6 f
|
||||
a b
|
||||
1 a
|
||||
2 b
|
||||
3 c
|
||||
3 c
|
||||
4 d
|
||||
5 e
|
||||
6 f
|
@ -2,6 +2,7 @@
|
||||
# Test of procedure analyse
|
||||
#
|
||||
|
||||
drop table if exists t1,t2;
|
||||
create table t1 (i int, j int);
|
||||
insert into t1 values (1,2), (3,4), (5,6), (7,8);
|
||||
select * from t1 procedure analyse();
|
||||
|
29
mysql-test/t/union.test
Normal file
29
mysql-test/t/union.test
Normal file
@ -0,0 +1,29 @@
|
||||
#
|
||||
# Test of unions
|
||||
#
|
||||
|
||||
drop table if exists t1,t2;
|
||||
CREATE TABLE t1 (a int not null, b char (10) not null);
|
||||
insert into t1 values(1,'a'),(2,'b'),(3,'c'),(3,'c');
|
||||
CREATE TABLE t2 (a int not null, b char (10) not null);
|
||||
insert into t2 values (3,'c'),(4,'d'),(5,'f'),(6,'e');
|
||||
|
||||
select a,b from t1 union select a,b from t2;
|
||||
select a,b from t1 union all select a,b from t2;
|
||||
select a,b from t1 union all select a,b from t2 order by b;
|
||||
select a,b from t1 union all select a,b from t2 union select 7,'g';
|
||||
select 0,'#' union select a,b from t1 union all select a,b from t2 union select 7,'gg';
|
||||
select a,b from t1 union select a,b from t1;
|
||||
select 't1',b,count(*) from t1 group by b UNION select 't2',b,count(*) from t2 group by b;
|
||||
|
||||
explain select a,b from t1 union all select a,b from t2;
|
||||
|
||||
# Test some error conditions with UNION
|
||||
--error 1213
|
||||
select a,b from t1 into outfile 'skr' union select a,b from t2;
|
||||
--error 1213
|
||||
select a,b from t1 order by a union select a,b from t2;
|
||||
--error 1214
|
||||
select a,b from t1 union select a from t2;
|
||||
|
||||
drop table t1,t2;
|
@ -1,16 +0,0 @@
|
||||
#
|
||||
# Test of unions
|
||||
#
|
||||
|
||||
drop table if exists t1,t2;
|
||||
CREATE TABLE t1 (a int not null, b char (10) not null);
|
||||
insert into t1 values(1,"a"),(2,"b"),(3,"c");
|
||||
CREATE TABLE t2 (a int not null, b char (10) not null);
|
||||
insert into t2 values (3,"c"),(4,"d"),(5,"e"),(6,"f");
|
||||
|
||||
|
||||
select a,b from t1 union select a,b from t2;
|
||||
|
||||
select a,b from t1 union all select a,b from t2;
|
||||
|
||||
drop table t1,t2;
|
@ -83,7 +83,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
|
||||
sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
|
||||
slave.cc sql_repl.cc \
|
||||
mini_client.cc mini_client_errors.c \
|
||||
md5.c stacktrace.c sql_unions.cc
|
||||
md5.c stacktrace.c sql_union.cc
|
||||
gen_lex_hash_SOURCES = gen_lex_hash.cc
|
||||
gen_lex_hash_LDADD = $(LDADD) $(CXXLDFLAGS)
|
||||
mysqlbinlog_SOURCES = mysqlbinlog.cc mini_client.cc net_serv.cc \
|
||||
|
@ -677,5 +677,6 @@ bool field_is_equal_to_item(Field *field,Item *item)
|
||||
#ifdef __GNUC__
|
||||
template class List<Item>;
|
||||
template class List_iterator<Item>;
|
||||
template class List_iterator_fast<Item>;
|
||||
template class List<List_item>;
|
||||
#endif
|
||||
|
@ -1129,7 +1129,7 @@ void Item_cond::update_used_tables()
|
||||
{
|
||||
used_tables_cache=0;
|
||||
const_item_cache=1;
|
||||
List_iterator<Item> li(list);
|
||||
List_iterator_fast<Item> li(list);
|
||||
Item *item;
|
||||
while ((item=li++))
|
||||
{
|
||||
@ -1143,7 +1143,7 @@ void Item_cond::update_used_tables()
|
||||
void Item_cond::print(String *str)
|
||||
{
|
||||
str->append('(');
|
||||
List_iterator<Item> li(list);
|
||||
List_iterator_fast<Item> li(list);
|
||||
Item *item;
|
||||
if ((item=li++))
|
||||
item->print(str);
|
||||
@ -1160,7 +1160,7 @@ void Item_cond::print(String *str)
|
||||
|
||||
longlong Item_cond_and::val_int()
|
||||
{
|
||||
List_iterator<Item> li(list);
|
||||
List_iterator_fast<Item> li(list);
|
||||
Item *item;
|
||||
while ((item=li++))
|
||||
{
|
||||
@ -1179,7 +1179,7 @@ longlong Item_cond_and::val_int()
|
||||
|
||||
longlong Item_cond_or::val_int()
|
||||
{
|
||||
List_iterator<Item> li(list);
|
||||
List_iterator_fast<Item> li(list);
|
||||
Item *item;
|
||||
null_value=0;
|
||||
while ((item=li++))
|
||||
|
@ -43,7 +43,7 @@ Item_func::Item_func(List<Item> &list)
|
||||
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
|
||||
{
|
||||
uint i=0;
|
||||
List_iterator<Item> li(list);
|
||||
List_iterator_fast<Item> li(list);
|
||||
Item *item;
|
||||
|
||||
while ((item=li++))
|
||||
@ -1983,7 +1983,7 @@ bool Item_func_match::fix_fields(THD *thd,struct st_table_list *tlist)
|
||||
|
||||
bool Item_func_match::fix_index()
|
||||
{
|
||||
List_iterator<Item> li(fields);
|
||||
List_iterator_fast<Item> li(fields);
|
||||
Item_field *item;
|
||||
uint ft_to_key[MAX_KEY], ft_cnt[MAX_KEY], fts=0, key;
|
||||
|
||||
|
258
sql/item_sum.cc
258
sql/item_sum.cc
@ -30,7 +30,7 @@ Item_sum::Item_sum(List<Item> &list)
|
||||
if ((args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
|
||||
{
|
||||
uint i=0;
|
||||
List_iterator<Item> li(list);
|
||||
List_iterator_fast<Item> li(list);
|
||||
Item *item;
|
||||
|
||||
while ((item=li++))
|
||||
@ -790,74 +790,71 @@ String *Item_std_field::val_str(String *str)
|
||||
|
||||
static int simple_raw_key_cmp(void* arg, byte* key1, byte* key2)
|
||||
{
|
||||
return memcmp(key1, key2, (int)arg);
|
||||
return memcmp(key1, key2, (int) arg);
|
||||
}
|
||||
|
||||
static int simple_str_key_cmp(void* arg, byte* key1, byte* key2)
|
||||
{
|
||||
return my_sortcmp(key1, key2, (int)arg);
|
||||
return my_sortcmp(key1, key2, (int) arg);
|
||||
}
|
||||
|
||||
// did not make this one static - at least gcc gets confused when
|
||||
// I try to declare a static function as a friend. If you can figure
|
||||
// out the syntax to make a static function a friend, make this one
|
||||
// static
|
||||
/*
|
||||
Did not make this one static - at least gcc gets confused when
|
||||
I try to declare a static function as a friend. If you can figure
|
||||
out the syntax to make a static function a friend, make this one
|
||||
static
|
||||
*/
|
||||
|
||||
int composite_key_cmp(void* arg, byte* key1, byte* key2)
|
||||
{
|
||||
Item_sum_count_distinct* item = (Item_sum_count_distinct*)arg;
|
||||
Field** field = item->table->field, **field_end;
|
||||
field_end = field + item->table->fields;
|
||||
for(; field < field_end; ++field)
|
||||
{
|
||||
int res;
|
||||
Field* f = *field;
|
||||
int len = f->pack_length();
|
||||
switch((*field)->type())
|
||||
{
|
||||
case FIELD_TYPE_STRING:
|
||||
case FIELD_TYPE_VAR_STRING:
|
||||
res = f->key_cmp(key1, key2);
|
||||
break;
|
||||
default:
|
||||
res = memcmp(key1, key2, len);
|
||||
break;
|
||||
}
|
||||
if(res)
|
||||
return res;
|
||||
key1 += len;
|
||||
key2 += len;
|
||||
}
|
||||
Field **field = item->table->field;
|
||||
Field **field_end= field + item->table->fields;
|
||||
uint32 *lengths=item->field_lengths;
|
||||
for (; field < field_end; ++field)
|
||||
{
|
||||
Field* f = *field;
|
||||
int len = *lengths++;
|
||||
int res = f->key_cmp(key1, key2);
|
||||
if (res)
|
||||
return res;
|
||||
key1 += len;
|
||||
key2 += len;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// helper function for walking the tree when we dump it to MyISAM -
|
||||
// tree_walk will call it for each
|
||||
// leaf
|
||||
/*
|
||||
helper function for walking the tree when we dump it to MyISAM -
|
||||
tree_walk will call it for each leaf
|
||||
*/
|
||||
|
||||
int dump_leaf(byte* key, uint32 count __attribute__((unused)),
|
||||
Item_sum_count_distinct* item)
|
||||
{
|
||||
char* buf = item->table->record[0];
|
||||
int error;
|
||||
// the first item->rec_offset bytes are taken care of with
|
||||
// restore_record(table,2) in setup()
|
||||
/*
|
||||
The first item->rec_offset bytes are taken care of with
|
||||
restore_record(table,2) in setup()
|
||||
*/
|
||||
memcpy(buf + item->rec_offset, key, item->tree.size_of_element);
|
||||
if ((error = item->table->file->write_row(buf)))
|
||||
{
|
||||
if (error != HA_ERR_FOUND_DUPP_KEY &&
|
||||
error != HA_ERR_FOUND_DUPP_UNIQUE)
|
||||
return 1;
|
||||
if (error != HA_ERR_FOUND_DUPP_KEY &&
|
||||
error != HA_ERR_FOUND_DUPP_UNIQUE)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Item_sum_count_distinct::~Item_sum_count_distinct()
|
||||
{
|
||||
if (table)
|
||||
free_tmp_table(current_thd, table);
|
||||
delete tmp_table_param;
|
||||
if(use_tree)
|
||||
if (use_tree)
|
||||
delete_tree(&tree);
|
||||
}
|
||||
|
||||
@ -895,91 +892,108 @@ bool Item_sum_count_distinct::setup(THD *thd)
|
||||
tmp_table_param->cleanup();
|
||||
}
|
||||
if (!(table=create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1,
|
||||
0, 0, current_lex->select->options | thd->options)))
|
||||
0, 0,
|
||||
current_lex->select->options | thd->options)))
|
||||
return 1;
|
||||
table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows
|
||||
table->no_rows=1;
|
||||
|
||||
|
||||
if(table->db_type == DB_TYPE_HEAP) // no blobs, otherwise it would be
|
||||
// MyISAM
|
||||
{
|
||||
qsort_cmp2 compare_key;
|
||||
void* cmp_arg;
|
||||
int key_len;
|
||||
// no blobs, otherwise it would be MyISAM
|
||||
if (table->db_type == DB_TYPE_HEAP)
|
||||
{
|
||||
qsort_cmp2 compare_key;
|
||||
void* cmp_arg;
|
||||
int key_len;
|
||||
|
||||
// to make things easier for dump_leaf if we ever have to dump to
|
||||
// MyISAM
|
||||
restore_record(table,2);
|
||||
// to make things easier for dump_leaf if we ever have to dump to MyISAM
|
||||
restore_record(table,2);
|
||||
|
||||
if(table->fields == 1) // if we have only one field, which is
|
||||
// the most common use of count(distinct), it is much faster
|
||||
// to use a simpler key compare method that can take advantage
|
||||
// of not having to worry about other fields
|
||||
{
|
||||
Field* field = table->field[0];
|
||||
switch(field->type())
|
||||
{
|
||||
// if we have a string, we must take care of charsets
|
||||
// and case sensitivity
|
||||
case FIELD_TYPE_STRING:
|
||||
case FIELD_TYPE_VAR_STRING:
|
||||
compare_key = (qsort_cmp2)(field->binary() ? simple_raw_key_cmp:
|
||||
simple_str_key_cmp);
|
||||
break;
|
||||
default: // since at this point we cannot have blobs
|
||||
// anything else can be compared with memcmp
|
||||
compare_key = (qsort_cmp2)simple_raw_key_cmp;
|
||||
break;
|
||||
}
|
||||
cmp_arg = (void*)(key_len = field->pack_length());
|
||||
rec_offset = 1;
|
||||
}
|
||||
else // too bad, cannot cheat - there is more than one field
|
||||
{
|
||||
bool all_binary = 1;
|
||||
Field** field, **field_end;
|
||||
field_end = (field = table->field) + table->fields;
|
||||
for(key_len = 0; field < field_end; ++field)
|
||||
{
|
||||
key_len += (*field)->pack_length();
|
||||
if(!(*field)->binary())
|
||||
all_binary = 0;
|
||||
}
|
||||
rec_offset = table->reclength - key_len;
|
||||
if(all_binary)
|
||||
{
|
||||
compare_key = (qsort_cmp2)simple_raw_key_cmp;
|
||||
cmp_arg = (void*)key_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
compare_key = (qsort_cmp2)composite_key_cmp ;
|
||||
cmp_arg = (void*)this;
|
||||
}
|
||||
}
|
||||
|
||||
init_tree(&tree, min(max_heap_table_size, sortbuff_size/16), 0,
|
||||
key_len, compare_key, 0, NULL, cmp_arg);
|
||||
use_tree = 1;
|
||||
|
||||
// the only time key_len could be 0 is if someone does
|
||||
// count(distinct) on a char(0) field - stupid thing to do,
|
||||
// but this has to be handled - otherwise someone can crash
|
||||
// the server with a DoS attack
|
||||
max_elements_in_tree = (key_len) ? max_heap_table_size/key_len :
|
||||
1;
|
||||
if (table->fields == 1)
|
||||
{
|
||||
/*
|
||||
If we have only one field, which is the most common use of
|
||||
count(distinct), it is much faster to use a simpler key
|
||||
compare method that can take advantage of not having to worry
|
||||
about other fields
|
||||
*/
|
||||
Field* field = table->field[0];
|
||||
switch(field->type())
|
||||
{
|
||||
/*
|
||||
If we have a string, we must take care of charsets and case
|
||||
sensitivity
|
||||
*/
|
||||
case FIELD_TYPE_STRING:
|
||||
case FIELD_TYPE_VAR_STRING:
|
||||
compare_key = (qsort_cmp2)(field->binary() ? simple_raw_key_cmp:
|
||||
simple_str_key_cmp);
|
||||
break;
|
||||
default:
|
||||
/*
|
||||
Since at this point we cannot have blobs anything else can
|
||||
be compared with memcmp
|
||||
*/
|
||||
compare_key = (qsort_cmp2)simple_raw_key_cmp;
|
||||
break;
|
||||
}
|
||||
cmp_arg = (void*)(key_len = field->pack_length());
|
||||
rec_offset = 1;
|
||||
}
|
||||
|
||||
else // too bad, cannot cheat - there is more than one field
|
||||
{
|
||||
bool all_binary = 1;
|
||||
Field** field, **field_end;
|
||||
field_end = (field = table->field) + table->fields;
|
||||
uint32 *lengths;
|
||||
if (!(field_lengths=
|
||||
(uint32*) thd->alloc(sizeof(uint32) * table->fields)))
|
||||
return 1;
|
||||
|
||||
for (key_len = 0, lengths=field_lengths; field < field_end; ++field)
|
||||
{
|
||||
uint32 length= (*field)->pack_length();
|
||||
key_len += length;
|
||||
*lengths++ = length;
|
||||
if (!(*field)->binary())
|
||||
all_binary = 0; // Can't break loop here
|
||||
}
|
||||
rec_offset = table->reclength - key_len;
|
||||
if (all_binary)
|
||||
{
|
||||
compare_key = (qsort_cmp2)simple_raw_key_cmp;
|
||||
cmp_arg = (void*)key_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
compare_key = (qsort_cmp2) composite_key_cmp ;
|
||||
cmp_arg = (void*)this;
|
||||
}
|
||||
}
|
||||
|
||||
init_tree(&tree, min(max_heap_table_size, sortbuff_size/16), 0,
|
||||
key_len, compare_key, 0, NULL, cmp_arg);
|
||||
use_tree = 1;
|
||||
|
||||
/*
|
||||
The only time key_len could be 0 is if someone does
|
||||
count(distinct) on a char(0) field - stupid thing to do,
|
||||
but this has to be handled - otherwise someone can crash
|
||||
the server with a DoS attack
|
||||
*/
|
||||
max_elements_in_tree = ((key_len) ? max_heap_table_size/key_len :
|
||||
1);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int Item_sum_count_distinct::tree_to_myisam()
|
||||
{
|
||||
if(create_myisam_from_heap(table, tmp_table_param,
|
||||
HA_ERR_RECORD_FILE_FULL, 1) ||
|
||||
tree_walk(&tree, (tree_walk_action)&dump_leaf, (void*)this,
|
||||
left_root_right))
|
||||
if (create_myisam_from_heap(table, tmp_table_param,
|
||||
HA_ERR_RECORD_FILE_FULL, 1) ||
|
||||
tree_walk(&tree, (tree_walk_action)&dump_leaf, (void*)this,
|
||||
left_root_right))
|
||||
return 1;
|
||||
delete_tree(&tree);
|
||||
use_tree = 0;
|
||||
@ -1011,18 +1025,20 @@ bool Item_sum_count_distinct::add()
|
||||
if ((*field)->is_real_null(0))
|
||||
return 0; // Don't count NULL
|
||||
|
||||
if(use_tree)
|
||||
if (use_tree)
|
||||
{
|
||||
/*
|
||||
If the tree got too big, convert to MyISAM, otherwise insert into the
|
||||
tree.
|
||||
*/
|
||||
if (tree.elements_in_tree > max_elements_in_tree)
|
||||
{
|
||||
// if the tree got too big, convert to MyISAM, otherwise
|
||||
// insert into the tree
|
||||
if(tree.elements_in_tree > max_elements_in_tree)
|
||||
{
|
||||
if(tree_to_myisam())
|
||||
return 1;
|
||||
}
|
||||
else if(!tree_insert(&tree, table->record[0] + rec_offset, 0))
|
||||
if(tree_to_myisam())
|
||||
return 1;
|
||||
}
|
||||
else if (!tree_insert(&tree, table->record[0] + rec_offset, 0))
|
||||
return 1;
|
||||
}
|
||||
else if ((error=table->file->write_row(table->record[0])))
|
||||
{
|
||||
if (error != HA_ERR_FOUND_DUPP_KEY &&
|
||||
@ -1039,7 +1055,7 @@ longlong Item_sum_count_distinct::val_int()
|
||||
{
|
||||
if (!table) // Empty query
|
||||
return LL(0);
|
||||
if(use_tree)
|
||||
if (use_tree)
|
||||
return tree.elements_in_tree;
|
||||
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
|
||||
return table->file->records;
|
||||
|
@ -146,6 +146,7 @@ class Item_sum_count_distinct :public Item_sum_int
|
||||
TABLE *table;
|
||||
table_map used_table_cache;
|
||||
bool fix_fields(THD *thd,TABLE_LIST *tables);
|
||||
uint32 *field_lengths;
|
||||
TMP_TABLE_PARAM *tmp_table_param;
|
||||
TREE tree;
|
||||
|
||||
|
@ -250,7 +250,7 @@ void key_unpack(String *to,TABLE *table,uint idx)
|
||||
|
||||
bool check_if_key_used(TABLE *table, uint idx, List<Item> &fields)
|
||||
{
|
||||
List_iterator<Item> f(fields);
|
||||
List_iterator_fast<Item> f(fields);
|
||||
KEY_PART_INFO *key_part,*key_part_end;
|
||||
for (key_part=table->key_info[idx].key_part,key_part_end=key_part+
|
||||
table->key_info[idx].key_parts ;
|
||||
|
@ -174,6 +174,9 @@ char* query_table_status(THD *thd,const char *db,const char *table_name);
|
||||
#define QUERY_NO_INDEX_USED OPTION_STATUS_NO_TRANS_UPDATE*2
|
||||
#define QUERY_NO_GOOD_INDEX_USED QUERY_NO_INDEX_USED*2
|
||||
|
||||
#define SELECT_NO_UNLOCK (QUERY_NO_GOOD_INDEX_USED*2)
|
||||
#define TMP_TABLE_ALL_COLUMNS (SELECT_NO_UNLOCK*2)
|
||||
|
||||
#define RAID_BLOCK_SIZE 1024
|
||||
|
||||
/* BINLOG_DUMP options */
|
||||
@ -305,8 +308,8 @@ int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields,
|
||||
int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
|
||||
List<Item_func_match> &ftfuncs,
|
||||
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
|
||||
uint select_type,select_result *result);
|
||||
int mysql_union(THD *thd,LEX *lex, uint no);
|
||||
ulong select_type,select_result *result);
|
||||
int mysql_union(THD *thd,LEX *lex);
|
||||
Field *create_tmp_field(TABLE *table,Item *item, Item::Type type,
|
||||
Item_result_field ***copy_func, Field **from_field,
|
||||
bool group,bool modify_item);
|
||||
@ -422,7 +425,8 @@ bool insert_fields(THD *thd,TABLE_LIST *tables,
|
||||
List_iterator<Item> *it);
|
||||
bool setup_tables(TABLE_LIST *tables);
|
||||
int setup_fields(THD *thd,TABLE_LIST *tables,List<Item> &item,
|
||||
bool set_query_id,List<Item> *sum_func_list);
|
||||
bool set_query_id,List<Item> *sum_func_list,
|
||||
bool allow_sum_func);
|
||||
int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
|
||||
int setup_ftfuncs(THD *thd,TABLE_LIST *tables, List<Item_func_match> &ftfuncs);
|
||||
void wait_for_refresh(THD *thd);
|
||||
|
@ -32,7 +32,7 @@ static bool find_range_key(TABLE_REF *ref, Field* field,COND *cond);
|
||||
|
||||
int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds)
|
||||
{
|
||||
List_iterator<Item> it(all_fields);
|
||||
List_iterator_fast<Item> it(all_fields);
|
||||
int const_result=1;
|
||||
bool recalc_const_item=0;
|
||||
table_map removed_tables=0;
|
||||
@ -205,7 +205,7 @@ uint count_table_entries(COND *cond,TABLE *table)
|
||||
if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC)
|
||||
return (cond->used_tables() & table->map) ? MAX_REF_PARTS+1 : 0;
|
||||
|
||||
List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
Item *item;
|
||||
uint count=0;
|
||||
while ((item=li++))
|
||||
@ -250,7 +250,7 @@ bool part_of_cond(COND *cond,Field *field)
|
||||
if (((Item_cond*) cond)->functype() == Item_func::COND_OR_FUNC)
|
||||
return 0; // Already checked
|
||||
|
||||
List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
Item *item;
|
||||
while ((item=li++))
|
||||
{
|
||||
|
@ -27,5 +27,11 @@ install-data-local:
|
||||
$(INSTALL_DATA) $(srcdir)/charsets/Index $(DESTDIR)$(pkgdatadir)/charsets/Index
|
||||
$(INSTALL_DATA) $(srcdir)/charsets/*.conf $(DESTDIR)$(pkgdatadir)/charsets
|
||||
|
||||
fix_errors:
|
||||
for lang in @AVAILABLE_LANGUAGES@; \
|
||||
do \
|
||||
../../extra/comp_err $(srcdir)/$$lang/errmsg.txt $(srcdir)/$$lang/errmsg.sys; \
|
||||
done
|
||||
|
||||
# Don't update the files from bitkeeper
|
||||
%::SCCS/s.%
|
||||
|
@ -223,3 +223,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -217,3 +217,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -214,3 +214,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -214,3 +214,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -218,3 +218,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -214,3 +214,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -217,3 +217,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -214,3 +214,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -216,3 +216,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -214,3 +214,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -216,3 +216,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -214,3 +214,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -216,3 +216,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -216,3 +216,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -218,3 +218,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -214,3 +214,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -218,3 +218,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -217,3 +217,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -222,3 +222,5 @@
|
||||
"Error connecting to master: %-.128s",
|
||||
"Error running query on master: %-.128s",
|
||||
"Error when executing command %s: %-.128s",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -215,3 +215,5 @@
|
||||
"Error de coneccion a master: %-128s",
|
||||
"Error executando el query en master: %-128%",
|
||||
"Error de %s: %-128%",
|
||||
"Wrong usage of %s and %s",
|
||||
"The used SELECT statements have a different number of columns",
|
||||
|
@ -205,12 +205,14 @@
|
||||
"Kunde inte initializera replications-strukturerna. Kontrollera privilegerna för 'master.info'",
|
||||
"Kunde inte starta en tråd för replikering",
|
||||
"Användare '%-.64s' har redan 'max_user_connections' aktiva inloggningar",
|
||||
"Du kan endast använda konstant-uttryck med SET",
|
||||
"Lock wait timeout exceeded",
|
||||
"The total number of locks exceeds the lock table size",
|
||||
"Update locks cannot be acquired during a READ UNCOMMITTED transaction",
|
||||
"Man kan endast använda konstant-uttryck med SET",
|
||||
"Fick inte ett lås i tid",
|
||||
"Antal lås överskrider antalet reserverade lås",
|
||||
"Updaterings-lås kan inte göras när man använder READ UNCOMMITTED",
|
||||
"DROP DATABASE är inte tillåtet när man har ett globalt läs-lås",
|
||||
"CREATE DATABASE är inte tillåtet när man har ett globalt läs-lås",
|
||||
"Fick fel vid anslutning till master: %-.128s",
|
||||
"Fick fel vid utförande av command på mastern: %-.128s",
|
||||
"Fick fel vid utförande av %s: %-.128s",
|
||||
"Felaktig använding av %s and %s",
|
||||
"SELECT kommandona har olika antal kolumner"
|
||||
|
@ -127,7 +127,7 @@ proc_analyse_init(THD *thd, ORDER *param, select_result *result,
|
||||
pc->f_end = pc->f_info + field_list.elements;
|
||||
pc->fields = field_list;
|
||||
|
||||
List_iterator<Item> it(pc->fields);
|
||||
List_iterator_fast<Item> it(pc->fields);
|
||||
f_info = pc->f_info;
|
||||
|
||||
Item *item;
|
||||
|
@ -189,7 +189,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
|
||||
bool
|
||||
send_fields(THD *thd,List<Item> &list,uint flag)
|
||||
{
|
||||
List_iterator<Item> it(list);
|
||||
List_iterator_fast<Item> it(list);
|
||||
Item *item;
|
||||
char buff[80];
|
||||
CONVERT *convert= (flag & 4) ? (CONVERT*) 0 : thd->convert_set;
|
||||
@ -1738,14 +1738,15 @@ find_item_in_list(Item *find,List<Item> &items)
|
||||
****************************************************************************/
|
||||
|
||||
int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
|
||||
bool set_query_id, List<Item> *sum_func_list)
|
||||
bool set_query_id, List<Item> *sum_func_list,
|
||||
bool allow_sum_func)
|
||||
{
|
||||
reg2 Item *item;
|
||||
List_iterator<Item> it(fields);
|
||||
DBUG_ENTER("setup_fields");
|
||||
|
||||
thd->set_query_id=set_query_id;
|
||||
thd->allow_sum_func= test(sum_func_list);
|
||||
thd->allow_sum_func= allow_sum_func;
|
||||
thd->where="field list";
|
||||
|
||||
while ((item=it++))
|
||||
@ -1761,7 +1762,8 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
|
||||
{
|
||||
if (item->fix_fields(thd,tables))
|
||||
DBUG_RETURN(-1); /* purecov: inspected */
|
||||
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM)
|
||||
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
|
||||
sum_func_list)
|
||||
item->split_sum_func(*sum_func_list);
|
||||
thd->used_tables|=item->used_tables();
|
||||
}
|
||||
@ -1816,7 +1818,7 @@ static key_map get_key_map_from_key_list(TABLE *table,
|
||||
List<String> *index_list)
|
||||
{
|
||||
key_map map=0;
|
||||
List_iterator<String> it(*index_list);
|
||||
List_iterator_fast<String> it(*index_list);
|
||||
String *name;
|
||||
uint pos;
|
||||
while ((name=it++))
|
||||
@ -1996,7 +1998,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
int
|
||||
fill_record(List<Item> &fields,List<Item> &values)
|
||||
{
|
||||
List_iterator<Item> f(fields),v(values);
|
||||
List_iterator_fast<Item> f(fields),v(values);
|
||||
Item *value;
|
||||
Item_field *field;
|
||||
DBUG_ENTER("fill_record");
|
||||
@ -2014,7 +2016,7 @@ fill_record(List<Item> &fields,List<Item> &values)
|
||||
int
|
||||
fill_record(Field **ptr,List<Item> &values)
|
||||
{
|
||||
List_iterator<Item> v(values);
|
||||
List_iterator_fast<Item> v(values);
|
||||
Item *value;
|
||||
DBUG_ENTER("fill_record");
|
||||
|
||||
|
@ -274,7 +274,7 @@ bool select_send::send_fields(List<Item> &list,uint flag)
|
||||
|
||||
bool select_send::send_data(List<Item> &items)
|
||||
{
|
||||
List_iterator<Item> li(items);
|
||||
List_iterator_fast<Item> li(items);
|
||||
String *packet= &thd->packet;
|
||||
DBUG_ENTER("send_data");
|
||||
|
||||
@ -299,12 +299,6 @@ bool select_send::send_data(List<Item> &items)
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
void select_send::send_error(uint errcode,const char *err)
|
||||
{
|
||||
::send_error(&thd->net,errcode,err);
|
||||
}
|
||||
|
||||
bool select_send::send_eof()
|
||||
{
|
||||
/* Unlock tables before sending packet to gain some speed */
|
||||
@ -367,7 +361,7 @@ select_export::prepare(List<Item> &list)
|
||||
}
|
||||
/* Check if there is any blobs in data */
|
||||
{
|
||||
List_iterator<Item> li(list);
|
||||
List_iterator_fast<Item> li(list);
|
||||
Item *item;
|
||||
while ((item=li++))
|
||||
{
|
||||
@ -414,7 +408,7 @@ bool select_export::send_data(List<Item> &items)
|
||||
Item *item;
|
||||
char *buff_ptr=buff;
|
||||
uint used_length=0,items_left=items.elements;
|
||||
List_iterator<Item> li(items);
|
||||
List_iterator_fast<Item> li(items);
|
||||
|
||||
if (my_b_write(&cache,(byte*) exchange->line_start->ptr(),
|
||||
exchange->line_start->length()))
|
||||
@ -607,7 +601,7 @@ select_dump::prepare(List<Item> &list __attribute__((unused)))
|
||||
|
||||
bool select_dump::send_data(List<Item> &items)
|
||||
{
|
||||
List_iterator<Item> li(items);
|
||||
List_iterator_fast<Item> li(items);
|
||||
char buff[MAX_FIELD_WIDTH];
|
||||
String tmp(buff,sizeof(buff)),*res;
|
||||
tmp.length(0);
|
||||
|
@ -413,6 +413,8 @@ public:
|
||||
|
||||
class JOIN;
|
||||
|
||||
void send_error(NET *net,uint sql_errno=0, const char *err=0);
|
||||
|
||||
class select_result :public Sql_alloc {
|
||||
protected:
|
||||
THD *thd;
|
||||
@ -423,7 +425,10 @@ public:
|
||||
virtual bool send_fields(List<Item> &list,uint flag)=0;
|
||||
virtual bool send_data(List<Item> &items)=0;
|
||||
virtual void initialize_tables (JOIN *join=0) {}
|
||||
virtual void send_error(uint errcode,const char *err)=0;
|
||||
virtual void send_error(uint errcode,const char *err)
|
||||
{
|
||||
::send_error(&thd->net,errcode,err);
|
||||
}
|
||||
virtual bool send_eof()=0;
|
||||
virtual void abort() {}
|
||||
};
|
||||
@ -434,7 +439,6 @@ public:
|
||||
select_send() {}
|
||||
bool send_fields(List<Item> &list,uint flag);
|
||||
bool send_data(List<Item> &items);
|
||||
void send_error(uint errcode,const char *err);
|
||||
bool send_eof();
|
||||
};
|
||||
|
||||
@ -458,6 +462,7 @@ public:
|
||||
bool send_eof();
|
||||
};
|
||||
|
||||
|
||||
class select_dump :public select_result {
|
||||
sql_exchange *exchange;
|
||||
File file;
|
||||
@ -475,30 +480,31 @@ public:
|
||||
void send_error(uint errcode,const char *err);
|
||||
bool send_eof();
|
||||
};
|
||||
|
||||
|
||||
class select_insert :public select_result {
|
||||
public:
|
||||
TABLE *table;
|
||||
List<Item> *fields;
|
||||
uint save_time_stamp;
|
||||
ulonglong last_insert_id;
|
||||
COPY_INFO info;
|
||||
bool unions;
|
||||
uint save_time_stamp;
|
||||
|
||||
select_insert(TABLE *table_par,List<Item> *fields_par,enum_duplicates duplic, bool u=false)
|
||||
:table(table_par),fields(fields_par), save_time_stamp(0),last_insert_id(0)
|
||||
{
|
||||
bzero((char*) &info,sizeof(info));
|
||||
info.handle_duplicates=duplic; unions = u;
|
||||
}
|
||||
select_insert(TABLE *table_par,List<Item> *fields_par,enum_duplicates duplic)
|
||||
:table(table_par),fields(fields_par), last_insert_id(0), save_time_stamp(0) {
|
||||
bzero((char*) &info,sizeof(info));
|
||||
info.handle_duplicates=duplic;
|
||||
}
|
||||
~select_insert();
|
||||
int prepare(List<Item> &list);
|
||||
bool send_fields(List<Item> &list,
|
||||
uint flag) { return 0; }
|
||||
bool send_fields(List<Item> &list, uint flag)
|
||||
{ return 0; }
|
||||
bool send_data(List<Item> &items);
|
||||
void send_error(uint errcode,const char *err);
|
||||
bool send_eof();
|
||||
};
|
||||
|
||||
|
||||
class select_create: public select_insert {
|
||||
ORDER *group;
|
||||
const char *db;
|
||||
@ -513,8 +519,8 @@ public:
|
||||
HA_CREATE_INFO *create_info_par,
|
||||
List<create_field> &fields_par,
|
||||
List<Key> &keys_par,
|
||||
List<Item> &select_fields,enum_duplicates duplic, bool u=false)
|
||||
:select_insert (NULL, &select_fields, duplic, u), db(db_name),
|
||||
List<Item> &select_fields,enum_duplicates duplic)
|
||||
:select_insert (NULL, &select_fields, duplic), db(db_name),
|
||||
name(table_name), extra_fields(&fields_par),keys(&keys_par),
|
||||
create_info(create_info_par),
|
||||
lock(0)
|
||||
@ -525,6 +531,22 @@ public:
|
||||
void abort();
|
||||
};
|
||||
|
||||
class select_union :public select_result {
|
||||
public:
|
||||
TABLE *table;
|
||||
COPY_INFO info;
|
||||
uint save_time_stamp;
|
||||
|
||||
select_union(TABLE *table_par);
|
||||
~select_union();
|
||||
int prepare(List<Item> &list);
|
||||
bool send_fields(List<Item> &list, uint flag)
|
||||
{ return 0; }
|
||||
bool send_data(List<Item> &items);
|
||||
bool send_eof();
|
||||
bool flush();
|
||||
};
|
||||
|
||||
/* Structs used when sorting */
|
||||
|
||||
typedef struct st_sort_field {
|
||||
|
@ -152,7 +152,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
|
||||
MYF(0),keyinfo->key_parts);
|
||||
goto err;
|
||||
}
|
||||
List_iterator<Item> it_ke(*key_expr);
|
||||
List_iterator_fast<Item> it_ke(*key_expr);
|
||||
Item *item;
|
||||
for (key_len=0 ; (item=it_ke++) ; key_part++)
|
||||
{
|
||||
|
@ -78,7 +78,8 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
|
||||
table_list.grant=table->grant;
|
||||
|
||||
thd->dupp_field=0;
|
||||
if (setup_tables(&table_list) || setup_fields(thd,&table_list,fields,1,0))
|
||||
if (setup_tables(&table_list) ||
|
||||
setup_fields(thd,&table_list,fields,1,0,0))
|
||||
return -1;
|
||||
if (thd->dupp_field)
|
||||
{
|
||||
@ -109,7 +110,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
|
||||
ulonglong id;
|
||||
COPY_INFO info;
|
||||
TABLE *table;
|
||||
List_iterator<List_item> its(values_list);
|
||||
List_iterator_fast<List_item> its(values_list);
|
||||
List_item *values;
|
||||
char *query=thd->query;
|
||||
DBUG_ENTER("mysql_insert");
|
||||
@ -151,7 +152,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
|
||||
save_time_stamp=table->time_stamp;
|
||||
values= its++;
|
||||
if (check_insert_fields(thd,table,fields,*values,1) ||
|
||||
setup_tables(table_list) || setup_fields(thd,table_list,*values,0,0))
|
||||
setup_tables(table_list) || setup_fields(thd,table_list,*values,0,0,0))
|
||||
{
|
||||
table->time_stamp=save_time_stamp;
|
||||
goto abort;
|
||||
@ -168,7 +169,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list, List<Item> &fields,
|
||||
table->time_stamp=save_time_stamp;
|
||||
goto abort;
|
||||
}
|
||||
if (setup_fields(thd,table_list,*values,0,0))
|
||||
if (setup_fields(thd,table_list,*values,0,0,0))
|
||||
{
|
||||
table->time_stamp=save_time_stamp;
|
||||
goto abort;
|
||||
@ -1237,14 +1238,14 @@ select_insert::prepare(List<Item> &values)
|
||||
|
||||
restore_record(table,2); // Get empty record
|
||||
table->next_number_field=table->found_next_number_field;
|
||||
thd->count_cuted_fields=1; /* calc cuted fields */
|
||||
thd->count_cuted_fields=1; // calc cuted fields
|
||||
thd->cuted_fields=0;
|
||||
if (info.handle_duplicates != DUP_REPLACE)
|
||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
if (info.handle_duplicates == DUP_IGNORE ||
|
||||
info.handle_duplicates == DUP_REPLACE)
|
||||
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
||||
table->file->deactivate_non_unique_index((ha_rows) 0);
|
||||
if (info.handle_duplicates != DUP_REPLACE)
|
||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
if (info.handle_duplicates == DUP_IGNORE ||
|
||||
info.handle_duplicates == DUP_REPLACE)
|
||||
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
||||
table->file->deactivate_non_unique_index((ha_rows) 0);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
@ -1319,8 +1320,7 @@ bool select_insert::send_eof()
|
||||
thd->cuted_fields);
|
||||
if (last_insert_id)
|
||||
thd->insert_id(last_insert_id); // For update log
|
||||
if (!unions)
|
||||
::send_ok(&thd->net,info.copied,last_insert_id,buff);
|
||||
::send_ok(&thd->net,info.copied,last_insert_id,buff);
|
||||
mysql_update_log.write(thd,thd->query,thd->query_length);
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
@ -1390,6 +1390,7 @@ bool select_create::send_data(List<Item> &values)
|
||||
|
||||
extern HASH open_cache;
|
||||
|
||||
|
||||
bool select_create::send_eof()
|
||||
{
|
||||
bool tmp=select_insert::send_eof();
|
||||
@ -1403,8 +1404,7 @@ bool select_create::send_eof()
|
||||
if (!table->tmp_table)
|
||||
hash_delete(&open_cache,(byte*) table);
|
||||
lock=0;
|
||||
if (!unions)
|
||||
table=0;
|
||||
table=0;
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
}
|
||||
return tmp;
|
||||
@ -1436,7 +1436,7 @@ void select_create::abort()
|
||||
*****************************************************************************/
|
||||
|
||||
#ifdef __GNUC__
|
||||
template class List_iterator<List_item>;
|
||||
template class List_iterator_fast<List_item>;
|
||||
template class I_List<delayed_insert>;
|
||||
template class I_List_iterator<delayed_insert>;
|
||||
template class I_List<delayed_row>;
|
||||
|
@ -115,7 +115,8 @@ typedef struct st_select_lex {
|
||||
List<List_item> when_list;
|
||||
SQL_LIST order_list,table_list,group_list;
|
||||
List<Item> item_list;
|
||||
List<String> interval_list,use_index, *use_index_ptr, ignore_index, *ignore_index_ptr;
|
||||
List<String> interval_list,use_index, *use_index_ptr,
|
||||
ignore_index, *ignore_index_ptr;
|
||||
List<Item_func_match> ftfunc_list;
|
||||
uint in_sum_expr, sort_default;
|
||||
bool create_refs;
|
||||
|
@ -20,3 +20,5 @@
|
||||
#endif
|
||||
|
||||
#include "mysql_priv.h"
|
||||
|
||||
list_node end_of_list;
|
||||
|
@ -34,25 +34,40 @@ public:
|
||||
/*
|
||||
** 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
|
||||
{
|
||||
public:
|
||||
list_node *next;
|
||||
void *info;
|
||||
list_node(void *info_par,list_node *next_par)
|
||||
:next(next_par),info(info_par)
|
||||
{}
|
||||
list_node() /* For end_of_list */
|
||||
{
|
||||
info=0;
|
||||
next= this;
|
||||
}
|
||||
friend class base_list;
|
||||
friend class base_list_iterator;
|
||||
};
|
||||
|
||||
extern list_node end_of_list;
|
||||
|
||||
class base_list :public Sql_alloc {
|
||||
protected:
|
||||
class list_node :public Sql_alloc
|
||||
{
|
||||
public:
|
||||
list_node *next;
|
||||
void *info;
|
||||
list_node(void *info_par,list_node *next_par) : next(next_par),info(info_par) {}
|
||||
friend class base_list;
|
||||
friend class base_list_iterator;
|
||||
};
|
||||
list_node *first,**last;
|
||||
|
||||
public:
|
||||
uint elements;
|
||||
|
||||
inline void empty() { elements=0; first=0; last=&first;}
|
||||
inline void empty() { elements=0; first= &end_of_list; last=&first;}
|
||||
inline base_list() { empty(); }
|
||||
inline base_list(const base_list &tmp) :Sql_alloc()
|
||||
{
|
||||
@ -62,7 +77,7 @@ public:
|
||||
}
|
||||
inline bool push_back(void *info)
|
||||
{
|
||||
if (((*last)=new list_node(info,0)))
|
||||
if (((*last)=new list_node(info, &end_of_list)))
|
||||
{
|
||||
last= &(*last)->next;
|
||||
elements++;
|
||||
@ -75,7 +90,7 @@ public:
|
||||
list_node *node=new list_node(info,first);
|
||||
if (node)
|
||||
{
|
||||
if (!first)
|
||||
if (last == &first)
|
||||
last= &node->next;
|
||||
first=node;
|
||||
elements++;
|
||||
@ -89,22 +104,21 @@ public:
|
||||
delete *prev;
|
||||
*prev=node;
|
||||
if (!--elements)
|
||||
{
|
||||
last= &first;
|
||||
first=0;
|
||||
}
|
||||
}
|
||||
inline void *pop(void)
|
||||
{
|
||||
if (!first) return 0;
|
||||
if (first == &end_of_list) return 0;
|
||||
list_node *tmp=first;
|
||||
first=first->next;
|
||||
if (!--elements)
|
||||
last= &first;
|
||||
return tmp->info;
|
||||
}
|
||||
inline void *head() { return first ? first->info : 0; }
|
||||
inline void **head_ref() { return first ? &first->info : 0; }
|
||||
inline void *head() { return first->info; }
|
||||
inline void **head_ref() { return first != &end_of_list ? &first->info : 0; }
|
||||
inline bool is_empty() { return first == &end_of_list ; }
|
||||
inline list_node *last_ref() { return &end_of_list; }
|
||||
friend class base_list_iterator;
|
||||
|
||||
protected:
|
||||
@ -122,7 +136,7 @@ protected:
|
||||
class base_list_iterator
|
||||
{
|
||||
base_list *list;
|
||||
base_list::list_node **el,**prev,*current;
|
||||
list_node **el,**prev,*current;
|
||||
public:
|
||||
base_list_iterator(base_list &list_par) :list(&list_par),el(&list_par.first),
|
||||
prev(0),current(0)
|
||||
@ -130,16 +144,22 @@ public:
|
||||
inline void *next(void)
|
||||
{
|
||||
prev=el;
|
||||
if (!(current= *el))
|
||||
return 0;
|
||||
current= *el;
|
||||
el= ¤t->next;
|
||||
return current->info;
|
||||
}
|
||||
inline void *next_fast(void)
|
||||
{
|
||||
list_node *tmp;
|
||||
tmp= *el;
|
||||
el= &tmp->next;
|
||||
return tmp->info;
|
||||
}
|
||||
inline void rewind(void)
|
||||
{
|
||||
el= &list->first;
|
||||
}
|
||||
void *replace(void *element)
|
||||
inline void *replace(void *element)
|
||||
{ // Return old element
|
||||
void *tmp=current->info;
|
||||
current->info=element;
|
||||
@ -148,7 +168,7 @@ public:
|
||||
void *replace(base_list &new_list)
|
||||
{
|
||||
void *ret_value=current->info;
|
||||
if (new_list.first)
|
||||
if (!new_list.is_empty())
|
||||
{
|
||||
*new_list.last=current->next;
|
||||
current->info=new_list.first->info;
|
||||
@ -175,7 +195,7 @@ public:
|
||||
}
|
||||
inline bool is_last(void)
|
||||
{
|
||||
return *el == 0;
|
||||
return el == &list->last_ref()->next;
|
||||
}
|
||||
};
|
||||
|
||||
@ -193,7 +213,7 @@ public:
|
||||
void delete_elements(void)
|
||||
{
|
||||
list_node *element,*next;
|
||||
for (element=first; element ; element=next)
|
||||
for (element=first; element != &end_of_list; element=next)
|
||||
{
|
||||
next=element->next;
|
||||
delete (T*) element->info;
|
||||
@ -208,13 +228,25 @@ template <class T> class List_iterator :public base_list_iterator
|
||||
public:
|
||||
List_iterator(List<T> &a) : base_list_iterator(a) {}
|
||||
inline T* operator++(int) { return (T*) base_list_iterator::next(); }
|
||||
inline void rewind(void) { base_list_iterator::rewind(); }
|
||||
inline T *replace(T *a) { return (T*) base_list_iterator::replace(a); }
|
||||
inline T *replace(List<T> &a) { return (T*) base_list_iterator::replace(a); }
|
||||
inline void remove(void) { base_list_iterator::remove(); }
|
||||
inline void after(T *a) { base_list_iterator::after(a); }
|
||||
inline T** ref(void) { return (T**) base_list_iterator::ref(); }
|
||||
inline bool is_last(void) { return base_list_iterator::is_last(); }
|
||||
};
|
||||
|
||||
template <class T> class List_iterator_fast :public base_list_iterator
|
||||
{
|
||||
protected:
|
||||
inline T *replace(T *a) { return (T*) 0; }
|
||||
inline T *replace(List<T> &a) { return (T*) 0; }
|
||||
inline void remove(void) { }
|
||||
inline void after(T *a) { }
|
||||
inline T** ref(void) { return (T**) 0; }
|
||||
|
||||
public:
|
||||
List_iterator_fast(List<T> &a) : base_list_iterator(a) {}
|
||||
inline T* operator++(int) { return (T*) base_list_iterator::next_fast(); }
|
||||
inline void rewind(void) { base_list_iterator::rewind(); }
|
||||
};
|
||||
|
||||
|
||||
|
@ -91,7 +91,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
||||
else
|
||||
{ // Part field list
|
||||
thd->dupp_field=0;
|
||||
if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0))
|
||||
if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0))
|
||||
DBUG_RETURN(-1);
|
||||
if (thd->dupp_field)
|
||||
{
|
||||
@ -102,7 +102,7 @@ int mysql_load(THD *thd,sql_exchange *ex,TABLE_LIST *table_list,
|
||||
|
||||
uint tot_length=0;
|
||||
bool use_blobs=0,use_timestamp=0;
|
||||
List_iterator<Item> it(fields);
|
||||
List_iterator_fast<Item> it(fields);
|
||||
|
||||
Item_field *field;
|
||||
while ((field=(Item_field*) it++))
|
||||
@ -269,7 +269,7 @@ static int
|
||||
read_fixed_length(THD *thd,COPY_INFO &info,TABLE *table,List<Item> &fields,
|
||||
READ_INFO &read_info)
|
||||
{
|
||||
List_iterator<Item> it(fields);
|
||||
List_iterator_fast<Item> it(fields);
|
||||
Item_field *sql_field;
|
||||
DBUG_ENTER("read_fixed_length");
|
||||
|
||||
@ -332,7 +332,7 @@ read_sep_field(THD *thd,COPY_INFO &info,TABLE *table,
|
||||
List<Item> &fields, READ_INFO &read_info,
|
||||
String &enclosed)
|
||||
{
|
||||
List_iterator<Item> it(fields);
|
||||
List_iterator_fast<Item> it(fields);
|
||||
Item_field *sql_field;
|
||||
uint enclosed_length;
|
||||
DBUG_ENTER("read_sep_field");
|
||||
|
130
sql/sql_parse.cc
130
sql/sql_parse.cc
@ -47,7 +47,8 @@ static void mysql_init_query(THD *thd);
|
||||
static void remove_escape(char *name);
|
||||
static void refresh_status(void);
|
||||
static bool append_file_to_dir(char **filename_ptr, char *table_name);
|
||||
static int link_in_large_list_and_check_acl(THD *thd,LEX *lex,SQL_LIST *tables);
|
||||
static int create_total_list_and_check_acl(THD *thd, LEX *lex,
|
||||
TABLE_LIST **result);
|
||||
|
||||
const char *any_db="*any*"; // Special symbol for check_access
|
||||
|
||||
@ -1737,10 +1738,10 @@ mysql_execute_command(void)
|
||||
}
|
||||
case SQLCOM_UNION_SELECT:
|
||||
{
|
||||
SQL_LIST *total=(SQL_LIST *) thd->calloc(sizeof(SQL_LIST));
|
||||
TABLE_LIST *total;
|
||||
if (select_lex->options & SELECT_DESCRIBE)
|
||||
lex->exchange=0;
|
||||
if ((res = link_in_large_list_and_check_acl(thd,lex,total)) == -1)
|
||||
if ((res = create_total_list_and_check_acl(thd,lex,&total)) == -1)
|
||||
{
|
||||
res=0;
|
||||
break;
|
||||
@ -1753,31 +1754,31 @@ mysql_execute_command(void)
|
||||
res=0;
|
||||
break;
|
||||
}
|
||||
if (!(res=open_and_lock_tables(thd,(TABLE_LIST *)total->first)))
|
||||
{
|
||||
/* Fix tables--to-be-unioned-from list to point at opened tables */
|
||||
for (SELECT_LEX *sl=&lex->select_lex;sl;sl=sl->next)
|
||||
{
|
||||
for (TABLE_LIST *cursor=(TABLE_LIST *)sl->table_list.first;cursor;cursor=cursor->next)
|
||||
cursor->table= ((TABLE_LIST*) cursor->table)->table;
|
||||
}
|
||||
ha_rows save_it=thd->offset_limit; thd->offset_limit=0;
|
||||
res=mysql_union(thd,lex, select_lex->select_number+1);
|
||||
thd->offset_limit=save_it;
|
||||
}
|
||||
if (!(res=open_and_lock_tables(thd, total)))
|
||||
{
|
||||
/* Fix tables--to-be-unioned-from list to point at opened tables */
|
||||
for (SELECT_LEX *sl=&lex->select_lex; sl; sl=sl->next)
|
||||
{
|
||||
for (TABLE_LIST *cursor= (TABLE_LIST *)sl->table_list.first;
|
||||
cursor;
|
||||
cursor=cursor->next)
|
||||
cursor->table= ((TABLE_LIST*) cursor->table)->table;
|
||||
}
|
||||
res=mysql_union(thd,lex);
|
||||
}
|
||||
close_thread_tables(thd);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_DROP_TABLE:
|
||||
{
|
||||
if (check_table_access(thd,DROP_ACL,tables))
|
||||
goto error; /* purecov: inspected */
|
||||
if (end_active_trans(thd))
|
||||
res= -1;
|
||||
else
|
||||
res = mysql_rm_table(thd,tables,lex->drop_if_exists);
|
||||
}
|
||||
break;
|
||||
{
|
||||
if (check_table_access(thd,DROP_ACL,tables))
|
||||
goto error; /* purecov: inspected */
|
||||
if (end_active_trans(thd))
|
||||
res= -1;
|
||||
else
|
||||
res = mysql_rm_table(thd,tables,lex->drop_if_exists);
|
||||
}
|
||||
break;
|
||||
case SQLCOM_DROP_INDEX:
|
||||
if (!tables->db)
|
||||
tables->db=thd->db;
|
||||
@ -2901,53 +2902,66 @@ TABLE_LIST *add_table_to_list(Table_ident *table, LEX_STRING *alias,
|
||||
DBUG_RETURN(ptr);
|
||||
}
|
||||
|
||||
static int link_in_large_list_and_check_acl(THD *thd,LEX *lex,SQL_LIST *tables)
|
||||
|
||||
/*
|
||||
** This is used for UNION to create a new table list of all used tables
|
||||
** The table_list->table entry in all used tables are set to point
|
||||
** to the entries in this list.
|
||||
*/
|
||||
|
||||
static int create_total_list_and_check_acl(THD *thd, LEX *lex,
|
||||
TABLE_LIST **result)
|
||||
{
|
||||
SELECT_LEX *sl; const char *current_db=thd->db ? thd->db : "";
|
||||
TABLE_LIST *ptr;
|
||||
for (sl=&lex->select_lex;sl;sl=sl->next)
|
||||
SELECT_LEX *sl;
|
||||
TABLE_LIST **new_table_list= result, *aux;
|
||||
const char *current_db=thd->db ? thd->db : ""; // QQ; To be removed
|
||||
|
||||
*new_table_list=0; // end result list
|
||||
for (sl=&lex->select_lex; sl; sl=sl->next)
|
||||
{
|
||||
if ((lex->sql_command == SQLCOM_UNION_SELECT) && (sl->order_list.first != (byte *)NULL) && (sl->next != (st_select_lex *)NULL))
|
||||
if ((lex->sql_command == SQLCOM_UNION_SELECT) &&
|
||||
sl->order_list.first && sl->next)
|
||||
{
|
||||
net_printf(&thd->net,ER_ILLEGAL_GRANT_FOR_TABLE); // correct error message will come here; only last SELECT can have ORDER BY
|
||||
net_printf(&thd->net,ER_WRONG_USAGE,"UNION","ORDER BY");
|
||||
return -1;
|
||||
}
|
||||
if (sl->table_list.first == (byte *)NULL) continue;
|
||||
TABLE_LIST *cursor,*aux=(TABLE_LIST*) sl->table_list.first;
|
||||
aux= (TABLE_LIST*) sl->table_list.first;
|
||||
if (aux)
|
||||
{
|
||||
if (check_table_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL , aux))
|
||||
return -1;
|
||||
for (;aux;aux=aux->next)
|
||||
TABLE_LIST *next;
|
||||
if (check_table_access(thd,
|
||||
lex->exchange ?
|
||||
SELECT_ACL | FILE_ACL : SELECT_ACL , aux))
|
||||
return -1;
|
||||
for (; aux; aux=next)
|
||||
{
|
||||
if (!aux->db)
|
||||
aux->db=(char *)current_db;
|
||||
for (cursor=(TABLE_LIST *)tables->first;cursor;cursor=cursor->next)
|
||||
if (!strcmp(cursor->db,aux->db) && (!strcmp(cursor->real_name,aux->real_name)))
|
||||
break;
|
||||
if (!cursor || !tables->first)
|
||||
{
|
||||
aux->lock_type= lex->lock_option;
|
||||
if (!tables->next)
|
||||
tables->next= (byte**) &tables->first;
|
||||
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
|
||||
return 1;
|
||||
ptr->db= aux->db; ptr->real_name=aux->real_name;
|
||||
ptr->name=aux->name; ptr->lock_type=aux->lock_type;
|
||||
ptr->updating=aux->updating;
|
||||
ptr->use_index=aux->use_index;
|
||||
ptr->ignore_index=aux->use_index;
|
||||
aux->table=(TABLE *)ptr;
|
||||
link_in_list(tables,(byte*)ptr,(byte**) &ptr->next);
|
||||
}
|
||||
else
|
||||
aux->table=(TABLE *)cursor;
|
||||
TABLE_LIST *cursor;
|
||||
next= aux->next;
|
||||
if (!aux->db)
|
||||
aux->db=(char *)current_db; // QQ; To be removed
|
||||
for (cursor= *result; cursor; cursor=cursor->next)
|
||||
if (!strcmp(cursor->db,aux->db) &&
|
||||
(!strcmp(cursor->real_name,aux->real_name)))
|
||||
break;
|
||||
if (!cursor)
|
||||
{
|
||||
/* Add not used table to the total table list */
|
||||
aux->lock_type= lex->lock_option;
|
||||
if (!(cursor = (TABLE_LIST *) thd->memdup((byte*) aux,
|
||||
sizeof(*aux))))
|
||||
return 1;
|
||||
*new_table_list= cursor;
|
||||
new_table_list= &cursor->next;
|
||||
*new_table_list=0; // end result list
|
||||
}
|
||||
aux->table=(TABLE *) cursor;
|
||||
}
|
||||
}
|
||||
}
|
||||
return (tables->first) ? 0 : 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void add_join_on(TABLE_LIST *b,Item *expr)
|
||||
{
|
||||
if (!b->on_expr)
|
||||
|
@ -152,7 +152,7 @@ int
|
||||
mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
List<Item_func_match> &ftfuncs,
|
||||
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
|
||||
uint select_options,select_result *result)
|
||||
ulong select_options,select_result *result)
|
||||
{
|
||||
TABLE *tmp_table;
|
||||
int error,tmp;
|
||||
@ -178,7 +178,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
thd->used_tables=0; // Updated by setup_fields
|
||||
|
||||
if (setup_tables(tables) ||
|
||||
setup_fields(thd,tables,fields,1,&all_fields) ||
|
||||
setup_fields(thd,tables,fields,1,&all_fields,1) ||
|
||||
setup_conds(thd,tables,&conds) ||
|
||||
setup_order(thd,tables,fields,all_fields,order) ||
|
||||
setup_group(thd,tables,fields,all_fields,group,&hidden_group_fields))
|
||||
@ -207,7 +207,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
if (!group)
|
||||
{
|
||||
uint flag=0;
|
||||
List_iterator<Item> it(fields);
|
||||
List_iterator_fast<Item> it(fields);
|
||||
Item *item;
|
||||
while ((item= it++))
|
||||
{
|
||||
@ -373,7 +373,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
error=(int) result->send_eof();
|
||||
}
|
||||
delete procedure;
|
||||
DBUG_RETURN(0);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
error = -1;
|
||||
@ -403,7 +403,8 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
error= 1; /* purecov: inspected */
|
||||
goto err; /* purecov: inspected */
|
||||
}
|
||||
if (join.const_tables && !thd->locked_tables)
|
||||
if (join.const_tables && !thd->locked_tables &&
|
||||
!(select_options & SELECT_NO_UNLOCK))
|
||||
{
|
||||
TABLE **table, **end;
|
||||
for (table=join.table, end=table + join.const_tables ;
|
||||
@ -571,7 +572,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
/* Perform FULLTEXT search before all regular searches */
|
||||
if (ftfuncs.elements)
|
||||
{
|
||||
List_iterator<Item_func_match> li(ftfuncs);
|
||||
List_iterator_fast<Item_func_match> li(ftfuncs);
|
||||
Item_func_match *ifm;
|
||||
DBUG_PRINT("info",("Performing FULLTEXT search"));
|
||||
thd->proc_info="FULLTEXT searching";
|
||||
@ -1268,7 +1269,7 @@ add_key_fields(JOIN_TAB *stat,KEY_FIELD **key_fields,uint *and_level,
|
||||
{
|
||||
if (cond->type() == Item_func::COND_ITEM)
|
||||
{
|
||||
List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
KEY_FIELD *org_key_fields= *key_fields;
|
||||
|
||||
if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
|
||||
@ -1433,7 +1434,7 @@ add_ft_keys(DYNAMIC_ARRAY *keyuse_array,
|
||||
}
|
||||
else if (cond->type() == Item::COND_ITEM)
|
||||
{
|
||||
List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
|
||||
if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
|
||||
{
|
||||
@ -2241,9 +2242,9 @@ make_simple_join(JOIN *join,TABLE *tmp_table)
|
||||
join->tables=1;
|
||||
join->const_tables=0;
|
||||
join->const_table_map=0;
|
||||
join->tmp_table_param.copy_field_count=join->tmp_table_param.field_count=
|
||||
join->tmp_table_param.sum_func_count= join->tmp_table_param.func_count=0;
|
||||
join->tmp_table_param.copy_field=0;
|
||||
join->tmp_table_param.field_count= join->tmp_table_param.sum_func_count=
|
||||
join->tmp_table_param.func_count=0;
|
||||
join->tmp_table_param.copy_field=join->tmp_table_param.copy_field_end=0;
|
||||
join->first_record=join->sort_and_group=0;
|
||||
join->sum_funcs=0;
|
||||
join->send_records=(ha_rows) 0;
|
||||
@ -2591,7 +2592,8 @@ join_free(JOIN *join)
|
||||
}
|
||||
// We are not using tables anymore
|
||||
// Unlock all tables. We may be in an INSERT .... SELECT statement.
|
||||
if (join->lock && join->thd->lock)
|
||||
if (join->lock && join->thd->lock &&
|
||||
!(join->select_options & SELECT_NO_UNLOCK))
|
||||
{
|
||||
mysql_unlock_read_tables(join->thd, join->lock);// Don't free join->lock
|
||||
join->lock=0;
|
||||
@ -2949,7 +2951,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_level,
|
||||
{
|
||||
bool and_level= ((Item_cond*) cond)->functype() ==
|
||||
Item_func::COND_AND_FUNC;
|
||||
List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
Item *item;
|
||||
I_List<COND_CMP> save;
|
||||
while ((item=li++))
|
||||
@ -3176,7 +3178,7 @@ const_expression_in_where(COND *cond, Item *comp_item, Item **const_item)
|
||||
{
|
||||
bool and_level= (((Item_cond*) cond)->functype()
|
||||
== Item_func::COND_AND_FUNC);
|
||||
List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
List_iterator_fast<Item> li(*((Item_cond*) cond)->argument_list());
|
||||
Item *item;
|
||||
while ((item=li++))
|
||||
{
|
||||
@ -3348,6 +3350,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
hidden_null_count, hidden_null_pack_length, hidden_field_count,
|
||||
blob_count,group_null_items;
|
||||
bool using_unique_constraint=0;
|
||||
bool not_all_columns= !(select_options & TMP_TABLE_ALL_COLUMNS);
|
||||
char *tmpname,path[FN_REFLEN];
|
||||
byte *pos,*group_buff;
|
||||
uchar *null_flags;
|
||||
@ -3438,24 +3441,27 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
reclength=blob_count=null_count=hidden_null_count=group_null_items=0;
|
||||
param->using_indirect_summary_function=0;
|
||||
|
||||
List_iterator<Item> li(fields);
|
||||
List_iterator_fast<Item> li(fields);
|
||||
Item *item;
|
||||
Field **tmp_from_field=from_field;
|
||||
while ((item=li++))
|
||||
{
|
||||
Item::Type type=item->type();
|
||||
if (item->with_sum_func && type != Item::SUM_FUNC_ITEM)
|
||||
if (not_all_columns)
|
||||
{
|
||||
/*
|
||||
Mark that the we have ignored an item that refers to a summary
|
||||
function. We need to know this if someone is going to use
|
||||
DISTINCT on the result.
|
||||
*/
|
||||
param->using_indirect_summary_function=1;
|
||||
continue;
|
||||
if (item->with_sum_func && type != Item::SUM_FUNC_ITEM)
|
||||
{
|
||||
/*
|
||||
Mark that the we have ignored an item that refers to a summary
|
||||
function. We need to know this if someone is going to use
|
||||
DISTINCT on the result.
|
||||
*/
|
||||
param->using_indirect_summary_function=1;
|
||||
continue;
|
||||
}
|
||||
if (item->const_item()) // We don't have to store this
|
||||
continue;
|
||||
}
|
||||
if (item->const_item()) // We don't have to store this
|
||||
continue;
|
||||
if (type == Item::SUM_FUNC_ITEM && !group && !save_sum_fields)
|
||||
{ /* Can't calc group yet */
|
||||
((Item_sum*) item)->result_field=0;
|
||||
@ -3466,7 +3472,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
{
|
||||
Field *new_field=
|
||||
create_tmp_field(table,arg,arg->type(),©_func,tmp_from_field,
|
||||
group != 0,1);
|
||||
group != 0,not_all_columns);
|
||||
if (!new_field)
|
||||
goto err; // Should be OOM
|
||||
tmp_from_field++;
|
||||
@ -3483,7 +3489,8 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
else
|
||||
{
|
||||
Field *new_field=create_tmp_field(table,item,type,©_func,
|
||||
tmp_from_field, group != 0,1);
|
||||
tmp_from_field, group != 0,
|
||||
not_all_columns);
|
||||
if (!new_field)
|
||||
{
|
||||
if (thd->fatal_error)
|
||||
@ -3620,7 +3627,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
|
||||
null_count=(null_count+7) & ~7; // move to next byte
|
||||
}
|
||||
|
||||
param->copy_field_count=(uint) (copy - param->copy_field);
|
||||
param->copy_field_end=copy;
|
||||
param->recinfo=recinfo;
|
||||
store_record(table,2); // Make empty default record
|
||||
|
||||
@ -6414,7 +6421,7 @@ setup_copy_fields(TMP_TABLE_PARAM *param,List<Item> &fields)
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
param->copy_field_count= (uint) (copy - param->copy_field);
|
||||
param->copy_field_end= copy;
|
||||
DBUG_RETURN(0);
|
||||
|
||||
err:
|
||||
@ -6432,17 +6439,16 @@ void
|
||||
copy_fields(TMP_TABLE_PARAM *param)
|
||||
{
|
||||
Copy_field *ptr=param->copy_field;
|
||||
Copy_field *end=ptr+param->copy_field_count;
|
||||
Copy_field *end=param->copy_field_end;
|
||||
|
||||
for ( ; ptr != end; ptr++)
|
||||
(*ptr->do_copy)(ptr);
|
||||
|
||||
List_iterator<Item> it(param->copy_funcs);
|
||||
List_iterator_fast<Item> &it=param->copy_funcs_it;
|
||||
it.rewind();
|
||||
Item_copy_string *item;
|
||||
while ((item = (Item_copy_string*) it++))
|
||||
{
|
||||
item->copy();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -118,19 +118,21 @@ typedef struct st_position { /* Used in find_best */
|
||||
class TMP_TABLE_PARAM {
|
||||
public:
|
||||
List<Item> copy_funcs;
|
||||
Copy_field *copy_field;
|
||||
List_iterator_fast<Item> copy_funcs_it;
|
||||
Copy_field *copy_field, *copy_field_end;
|
||||
byte *group_buff;
|
||||
Item_result_field **funcs;
|
||||
MI_COLUMNDEF *recinfo,*start_recinfo;
|
||||
KEY *keyinfo;
|
||||
ha_rows end_write_records;
|
||||
uint copy_field_count,field_count,sum_func_count,func_count;
|
||||
uint field_count,sum_func_count,func_count;
|
||||
uint hidden_field_count;
|
||||
uint group_parts,group_length;
|
||||
uint quick_group;
|
||||
bool using_indirect_summary_function;
|
||||
|
||||
TMP_TABLE_PARAM() :copy_field(0), group_parts(0), group_length(0)
|
||||
TMP_TABLE_PARAM()
|
||||
:copy_funcs_it(copy_funcs), copy_field(0), group_parts(0), group_length(0)
|
||||
{}
|
||||
~TMP_TABLE_PARAM()
|
||||
{
|
||||
|
@ -72,7 +72,7 @@ mysqld_show_dbs(THD *thd,const char *wild)
|
||||
DBUG_RETURN(1);
|
||||
if (mysql_find_files(thd,&files,NullS,mysql_data_home,wild,1))
|
||||
DBUG_RETURN(1);
|
||||
List_iterator<char> it(files);
|
||||
List_iterator_fast<char> it(files);
|
||||
while ((file_name=it++))
|
||||
{
|
||||
if (!opt_safe_show_db || thd->master_access ||
|
||||
@ -154,7 +154,7 @@ int mysqld_show_tables(THD *thd,const char *db,const char *wild)
|
||||
DBUG_RETURN(1);
|
||||
if (mysql_find_files(thd,&files,db,path,wild,0))
|
||||
DBUG_RETURN(-1);
|
||||
List_iterator<char> it(files);
|
||||
List_iterator_fast<char> it(files);
|
||||
while ((file_name=it++))
|
||||
{
|
||||
thd->packet.length(0);
|
||||
@ -284,7 +284,7 @@ int mysqld_extend_show_tables(THD *thd,const char *db,const char *wild)
|
||||
|
||||
if (mysql_find_files(thd,&files,db,path,wild,0))
|
||||
DBUG_RETURN(-1);
|
||||
List_iterator<char> it(files);
|
||||
List_iterator_fast<char> it(files);
|
||||
while ((file_name=it++))
|
||||
{
|
||||
TABLE_LIST table_list;
|
||||
@ -1165,6 +1165,6 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables)
|
||||
}
|
||||
|
||||
#ifdef __GNUC__
|
||||
template class List_iterator<char>;
|
||||
template class List_iterator_fast<char>;
|
||||
template class List<char>;
|
||||
#endif
|
||||
|
@ -669,7 +669,7 @@ TABLE *create_table_from_items(THD *thd, HA_CREATE_INFO *create_info,
|
||||
DBUG_ENTER("create_table_from_items");
|
||||
|
||||
/* Add selected items to field list */
|
||||
List_iterator<Item> it(*items);
|
||||
List_iterator_fast<Item> it(*items);
|
||||
Item *item;
|
||||
Field *tmp_field;
|
||||
tmp_table.db_create_options=0;
|
||||
|
217
sql/sql_union.cc
Normal file
217
sql/sql_union.cc
Normal file
@ -0,0 +1,217 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
|
||||
/*
|
||||
UNION of select's
|
||||
UNION's were introduced by Monty and Sinisa <sinisa@mysql.com>
|
||||
*/
|
||||
|
||||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_select.h"
|
||||
|
||||
|
||||
int mysql_union(THD *thd, LEX *lex)
|
||||
{
|
||||
SELECT_LEX *sl, *last_sl;
|
||||
ORDER *order;
|
||||
List<Item> item_list;
|
||||
/* TABLE_LIST *s=(TABLE_LIST*) lex->select_lex.table_list.first; */
|
||||
TABLE *table;
|
||||
TABLE_LIST *first_table, result_table_list;
|
||||
TMP_TABLE_PARAM tmp_table_param;
|
||||
select_result *result;
|
||||
select_union *union_result;
|
||||
int res;
|
||||
uint elements;
|
||||
DBUG_ENTER("mysql_union");
|
||||
|
||||
/* Find last select part as it's here ORDER BY and GROUP BY is stored */
|
||||
elements= lex->select_lex.item_list.elements;
|
||||
for (last_sl= &lex->select_lex;
|
||||
last_sl->next;
|
||||
last_sl=last_sl->next)
|
||||
{
|
||||
if (elements != last_sl->next->item_list.elements)
|
||||
{
|
||||
my_error(ER_WRONG_NUMBER_OF_COLUMNS_IN_SELECT,MYF(0));
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
order = (ORDER *) last_sl->order_list.first;
|
||||
{
|
||||
Item *item;
|
||||
List_iterator<Item> it(lex->select_lex.item_list);
|
||||
|
||||
/* Create a list of items that will be in the result set */
|
||||
first_table= (TABLE_LIST*) lex->select_lex.table_list.first;
|
||||
while ((item= it++))
|
||||
if (item_list.push_back(item))
|
||||
DBUG_RETURN(-1);
|
||||
if (setup_fields(thd,first_table,item_list,0,0,1))
|
||||
DBUG_RETURN(-1);
|
||||
}
|
||||
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
|
||||
tmp_table_param.field_count=elements;
|
||||
if (!(table=create_tmp_table(thd, &tmp_table_param, item_list,
|
||||
(ORDER*) 0, !lex->union_option,
|
||||
1, 0,
|
||||
(lex->select_lex.options | thd->options |
|
||||
TMP_TABLE_ALL_COLUMNS))))
|
||||
DBUG_RETURN(-1);
|
||||
table->file->extra(HA_EXTRA_WRITE_CACHE);
|
||||
table->file->extra(HA_EXTRA_IGNORE_DUP_KEY);
|
||||
bzero((char*) &result_table_list,sizeof(result_table_list));
|
||||
result_table_list.db= (char*) "";
|
||||
result_table_list.real_name=result_table_list.name=(char*) "union";
|
||||
result_table_list.table=table;
|
||||
|
||||
if (!(union_result=new select_union(table)))
|
||||
{
|
||||
res= -1;
|
||||
goto exit;
|
||||
}
|
||||
for (sl= &lex->select_lex; sl; sl=sl->next)
|
||||
{
|
||||
thd->offset_limit=sl->offset_limit;
|
||||
thd->select_limit=sl->select_limit+sl->offset_limit;
|
||||
if (thd->select_limit < sl->select_limit)
|
||||
thd->select_limit= HA_POS_ERROR; // no limit
|
||||
if (thd->select_limit == HA_POS_ERROR)
|
||||
sl->options&= ~OPTION_FOUND_ROWS;
|
||||
|
||||
res=mysql_select(thd,(TABLE_LIST*) sl->table_list.first,
|
||||
sl->item_list,
|
||||
sl->where,
|
||||
sl->ftfunc_list,
|
||||
(ORDER*) 0,
|
||||
(ORDER*) sl->group_list.first,
|
||||
sl->having,
|
||||
(ORDER*) NULL,
|
||||
sl->options | thd->options | SELECT_NO_UNLOCK,
|
||||
union_result);
|
||||
if (res)
|
||||
goto exit;
|
||||
}
|
||||
if (union_result->flush())
|
||||
{
|
||||
res= 1; // Error is already sent
|
||||
goto exit;
|
||||
}
|
||||
delete union_result;
|
||||
|
||||
/*
|
||||
Sinisa, we must also be able to handle
|
||||
CREATE TABLE ... and INSERT ... SELECT with unions
|
||||
|
||||
To do this, it's probably best that we add a new handle_select() function
|
||||
which takes 'select_result' as parameter and let this internally handle
|
||||
SELECT with and without unions.
|
||||
*/
|
||||
|
||||
if (lex->exchange)
|
||||
{
|
||||
if (lex->exchange->dumpfile)
|
||||
result=new select_dump(lex->exchange);
|
||||
else
|
||||
result=new select_export(lex->exchange);
|
||||
}
|
||||
else
|
||||
result=new select_send();
|
||||
res =-1;
|
||||
if (result)
|
||||
{
|
||||
/* Create a list of fields in the temporary table */
|
||||
List_iterator<Item> it(item_list);
|
||||
Field **field;
|
||||
List<Item_func_match> ftfunc_list;
|
||||
ftfunc_list.empty();
|
||||
|
||||
for (field=table->field ; *field ; field++)
|
||||
{
|
||||
(void) it++;
|
||||
(void) it.replace(new Item_field(*field));
|
||||
}
|
||||
if (!thd->fatal_error) // Check if EOM
|
||||
res=mysql_select(thd,&result_table_list,
|
||||
item_list, NULL, ftfunc_list, order,
|
||||
(ORDER*) NULL, NULL, (ORDER*) NULL,
|
||||
thd->options, result);
|
||||
if (res)
|
||||
result->abort();
|
||||
delete result;
|
||||
}
|
||||
|
||||
exit:
|
||||
free_tmp_table(thd,table);
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
** store records in temporary table for UNION
|
||||
***************************************************************************/
|
||||
|
||||
select_union::select_union(TABLE *table_par)
|
||||
:table(table_par)
|
||||
{
|
||||
bzero((char*) &info,sizeof(info));
|
||||
/*
|
||||
We can always use DUP_IGNORE because the temporary table will only
|
||||
contain a unique key if we are using not using UNION ALL
|
||||
*/
|
||||
info.handle_duplicates=DUP_IGNORE;
|
||||
}
|
||||
|
||||
select_union::~select_union()
|
||||
{
|
||||
}
|
||||
|
||||
int select_union::prepare(List<Item> &list)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool select_union::send_data(List<Item> &values)
|
||||
{
|
||||
if (thd->offset_limit)
|
||||
{ // using limit offset,count
|
||||
thd->offset_limit--;
|
||||
return 0;
|
||||
}
|
||||
fill_record(table->field,values);
|
||||
return write_record(table,&info) ? 1 : 0;
|
||||
}
|
||||
|
||||
bool select_union::send_eof()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool select_union::flush()
|
||||
{
|
||||
int error,error2;
|
||||
error=table->file->extra(HA_EXTRA_NO_CACHE);
|
||||
if (error)
|
||||
{
|
||||
table->file->print_error(error,MYF(0));
|
||||
::send_error(&thd->net);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
/* Copyright (C) 2000 MySQL AB
|
||||
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; either version 2 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
|
||||
/* UNION of select's */
|
||||
|
||||
/* UNION's were introduced by Monty and Sinisa <sinisa@mysql.com> */
|
||||
|
||||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_select.h"
|
||||
|
||||
/* Union of selects */
|
||||
|
||||
|
||||
int mysql_union(THD *thd,LEX *lex,uint no_of_selects)
|
||||
{
|
||||
SELECT_LEX *sl, *for_order=&lex->select_lex; int res=0;
|
||||
TABLE *table=(TABLE *)NULL; TABLE_LIST *resulting=(TABLE_LIST *)NULL;
|
||||
for (;for_order->next;for_order=for_order->next);
|
||||
ORDER *some_order = (ORDER *)for_order->order_list.first;
|
||||
List<Item> list;
|
||||
List_iterator<Item> it(lex->select_lex.item_list);
|
||||
Item *item;
|
||||
TABLE_LIST *s=(TABLE_LIST*) lex->select_lex.table_list.first;
|
||||
while ((item= it++))
|
||||
if (list.push_back(item))
|
||||
return -1;
|
||||
if (setup_fields(thd,s,list,0,0))
|
||||
return -1;
|
||||
TMP_TABLE_PARAM *tmp_table_param= new TMP_TABLE_PARAM;
|
||||
count_field_types(tmp_table_param,list,0);
|
||||
tmp_table_param->end_write_records= HA_POS_ERROR; tmp_table_param->copy_field=0;
|
||||
tmp_table_param->copy_field_count=tmp_table_param->field_count=
|
||||
tmp_table_param->sum_func_count= tmp_table_param->func_count=0;
|
||||
if (!(table=create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, !lex->union_option,
|
||||
0, 0, lex->select_lex.options | thd->options)))
|
||||
return 1;
|
||||
if (!(resulting = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))))
|
||||
return 1;
|
||||
resulting->db=s->db ? s->db : thd->db;
|
||||
resulting->real_name=table->real_name;
|
||||
resulting->name=table->table_name;
|
||||
resulting->table=table;
|
||||
|
||||
for (sl=&lex->select_lex;sl;sl=sl->next)
|
||||
{
|
||||
TABLE_LIST *tables=(TABLE_LIST*) sl->table_list.first;
|
||||
select_insert *result;
|
||||
if ((result=new select_insert(table,&list, DUP_IGNORE, true)))
|
||||
{
|
||||
res=mysql_select(thd,tables,sl->item_list,
|
||||
sl->where,
|
||||
sl->ftfunc_list,
|
||||
(ORDER*) some_order,
|
||||
(ORDER*) sl->group_list.first,
|
||||
sl->having,
|
||||
(ORDER*) NULL,
|
||||
sl->options | thd->options,
|
||||
result);
|
||||
delete result;
|
||||
if (res)
|
||||
return res;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
select_result *result;
|
||||
List<Item_func_match> ftfunc_list;
|
||||
ftfunc_list.empty();
|
||||
if (lex->exchange)
|
||||
{
|
||||
if (lex->exchange->dumpfile)
|
||||
result=new select_dump(lex->exchange);
|
||||
else
|
||||
result=new select_export(lex->exchange);
|
||||
}
|
||||
else result=new select_send();
|
||||
if (result)
|
||||
{
|
||||
res=mysql_select(thd,resulting,list,
|
||||
NULL,
|
||||
ftfunc_list,
|
||||
(ORDER*) NULL,
|
||||
(ORDER*) NULL,
|
||||
NULL,
|
||||
(ORDER*) NULL,
|
||||
thd->options,
|
||||
result);
|
||||
if (res)
|
||||
result->abort();
|
||||
delete result;
|
||||
}
|
||||
else
|
||||
res=-1;
|
||||
return res;
|
||||
}
|
@ -90,7 +90,7 @@ int mysql_update(THD *thd,
|
||||
|
||||
/* Check the fields we are going to modify */
|
||||
table->grant.want_privilege=want_privilege;
|
||||
if (setup_fields(thd,table_list,fields,1,0))
|
||||
if (setup_fields(thd,table_list,fields,1,0,0))
|
||||
DBUG_RETURN(-1); /* purecov: inspected */
|
||||
if (table->timestamp_field)
|
||||
{
|
||||
@ -103,7 +103,7 @@ int mysql_update(THD *thd,
|
||||
|
||||
/* Check values */
|
||||
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
|
||||
if (setup_fields(thd,table_list,values,0,0))
|
||||
if (setup_fields(thd,table_list,values,0,0,0))
|
||||
{
|
||||
table->time_stamp=save_time_stamp; // Restore timestamp pointer
|
||||
DBUG_RETURN(-1); /* purecov: inspected */
|
||||
|
@ -1319,7 +1319,7 @@ select:
|
||||
SELECT_SYM
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
if (lex->sql_command!=SQLCOM_UNION_SELECT) lex->sql_command= SQLCOM_SELECT;
|
||||
lex->sql_command= SQLCOM_SELECT;
|
||||
lex->lock_option=TL_READ;
|
||||
mysql_init_select(lex);
|
||||
}
|
||||
@ -3281,7 +3281,7 @@ opt_table:
|
||||
lex->grant = DB_ACLS & ~GRANT_ACL;
|
||||
else if (lex->columns.elements)
|
||||
{
|
||||
net_printf(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
|
||||
send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
@ -3293,7 +3293,7 @@ opt_table:
|
||||
lex->grant = DB_ACLS & ~GRANT_ACL;
|
||||
else if (lex->columns.elements)
|
||||
{
|
||||
net_printf(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
|
||||
send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
@ -3305,7 +3305,7 @@ opt_table:
|
||||
lex->grant = GLOBAL_ACLS & ~GRANT_ACL;
|
||||
else if (lex->columns.elements)
|
||||
{
|
||||
net_printf(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
|
||||
send_error(&lex->thd->net,ER_ILLEGAL_GRANT_FOR_TABLE);
|
||||
YYABORT;
|
||||
}
|
||||
}
|
||||
@ -3407,11 +3407,20 @@ union_list:
|
||||
UNION_SYM union_option
|
||||
{
|
||||
LEX *lex=Lex;
|
||||
if (lex->exchange) YYABORT; /* Only the last SELECT can have INTO...... */
|
||||
lex->sql_command=SQLCOM_UNION_SELECT;
|
||||
mysql_new_select(lex); lex->select->linkage=UNION_TYPE;
|
||||
if (lex->exchange)
|
||||
{
|
||||
/* Only the last SELECT can have INTO...... */
|
||||
net_printf(¤t_thd->net, ER_WRONG_USAGE,"UNION","INTO");
|
||||
YYABORT;
|
||||
}
|
||||
mysql_new_select(lex);
|
||||
lex->select->linkage=UNION_TYPE;
|
||||
}
|
||||
select
|
||||
select
|
||||
{
|
||||
Lex->sql_command=SQLCOM_UNION_SELECT;
|
||||
}
|
||||
|
||||
|
||||
union_option:
|
||||
/* empty */ {}
|
||||
|
Loading…
x
Reference in New Issue
Block a user