Commit d56e23f6 authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua

fixed subselects with temporary tables (SCRUM)

fixed memory leacks
parent 710881e4
......@@ -81,21 +81,18 @@ select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1);
a b
1 7
2 7
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
union (select * from t4 order by a limit 2) limit 3;
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 order by a limit 2) limit 3;
a b
1 7
2 7
3 8
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
a b
1 7
2 7
3 8
4 8
explain select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
explain select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 ALL NULL NULL NULL NULL 2 Using where
2 SUBSELECT t3 ALL NULL NULL NULL NULL 3 Using filesort
......@@ -330,19 +327,15 @@ Unknown column 'a' in 'having clause'
SELECT * from t2 where topic IN (SELECT topic FROM t2 GROUP BY date);
mot topic date pseudo
joce 40143 2002-10-22 joce
joce 43506 2002-10-22 joce
SELECT * from t2 where topic IN (SELECT topic FROM t2 GROUP BY date HAVING topic < 4100);
mot topic date pseudo
joce 43506 2002-10-22 joce
SELECT * from t2 where topic IN (SELECT SUM(topic) FROM t1);
mot topic date pseudo
SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY date);
mot topic date pseudo
joce 40143 2002-10-22 joce
joce 43506 2002-10-22 joce
SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY date HAVING topic < 4100);
mot topic date pseudo
joce 43506 2002-10-22 joce
SELECT * from t2 where topic = any (SELECT SUM(topic) FROM t1);
mot topic date pseudo
SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY date);
......@@ -351,6 +344,7 @@ joce 40143 2002-10-22 joce
SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY date HAVING topic < 4100);
mot topic date pseudo
joce 40143 2002-10-22 joce
joce 43506 2002-10-22 joce
SELECT * from t2 where topic = all (SELECT SUM(topic) FROM t2);
mot topic date pseudo
SELECT * from t2 where topic <> any (SELECT SUM(topic) FROM t2);
......
......@@ -42,12 +42,9 @@ select (select a from t3), a from t2;
select * from t2 where t2.a=(select a from t1);
insert into t3 values (6),(7),(3);
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1);
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
union (select * from t4 order by a limit 2) limit 3;
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
explain select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 order by a limit 2) limit 3;
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
explain select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1) union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
select (select a from t3 where a<t2.a*4 order by 1 desc limit 1), a from t2;
select (select t3.a from t3 where a<8 order by 1 desc limit 1), a from
(select * from t2 where a>1) as tt;
......@@ -190,7 +187,10 @@ SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY date);
SELECT * from t2 where topic = any (SELECT topic FROM t2 GROUP BY date HAVING topic < 4100);
SELECT * from t2 where topic = any (SELECT SUM(topic) FROM t1);
SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY date);
SELECT topic FROM t2 GROUP BY date;
SELECT topic FROM t2 GROUP BY date HAVING topic < 4100;
SELECT * from t2 where topic = all (SELECT topic FROM t2 GROUP BY date HAVING topic < 4100);
SELECT *, date as fff from t2 where not (SELECT date FROM t2 GROUP BY date HAVING topic < 4100 and fff!=date);
SELECT * from t2 where topic = all (SELECT SUM(topic) FROM t2);
SELECT * from t2 where topic <> any (SELECT SUM(topic) FROM t2);
drop table t1,t2;
......
......@@ -46,6 +46,31 @@ Item::Item():
loop_id= 0;
}
Item::Item(Item &item):
loop_id(0),
str_value(item.str_value),
name(item.name),
max_length(item.max_length),
marker(item.marker),
decimals(item.decimals),
maybe_null(item.maybe_null),
null_value(item.null_value),
unsigned_flag(item.unsigned_flag),
with_sum_func(item.with_sum_func),
fixed(item.fixed)
{
next=current_thd->free_list; // Put in free list
current_thd->free_list= this;
}
Item_ident::Item_ident(Item_ident &item):
Item(item),
db_name(item.db_name),
table_name(item.table_name),
field_name(item.field_name),
depended_from(item.depended_from)
{}
bool Item::check_loop(uint id)
{
DBUG_ENTER("Item::check_loop");
......@@ -153,6 +178,11 @@ Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name)
fixed= 1; // This item is not needed in fix_fields
}
Item_field::Item_field(Item_field &item):
Item_ident(item),
field(item.field),
result_field(item.result_field)
{}
void Item_field::set_field(Field *field_par)
{
......@@ -262,6 +292,13 @@ table_map Item_field::used_tables() const
return field->table->map;
}
Item * Item_field::get_tmp_table_item()
{
Item_field *new_item= new Item_field(*this);
if (new_item)
new_item->field= new_item->result_field;
return new_item;
}
String *Item_int::val_str(String *str)
{
......@@ -535,6 +572,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
SELECT_LEX *last= 0;
Item **refer= (Item **)not_found_item;
uint counter= 0;
// Prevent using outer fields in subselects, that is not supported now
SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select;
if (cursel->linkage != DERIVED_TABLE_TYPE)
......@@ -546,7 +584,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
(last= sl)->get_table_list(),
0)) != not_found_field)
break;
if ((refer= find_item_in_list(this, sl->item_list,
if ((refer= find_item_in_list(this, sl->item_list, &counter,
REPORT_EXCEPT_NOT_FOUND)) !=
(Item **)not_found_item)
break;
......@@ -565,8 +603,16 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
}
else if (refer != (Item **)not_found_item)
{
if (!(*refer)->fixed)
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
"forward reference in item list");
return -1;
}
Item_ref *r;
*ref= r= new Item_ref(refer, (char *)table_name,
*ref= r= new Item_ref(last->ref_pointer_array + counter-1
, (char *)table_name,
(char *)field_name);
if (!r)
return 1;
......@@ -930,6 +976,7 @@ bool Item_null::send(THD *thd, String *packet)
bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
uint counter= 0;
if (!ref)
{
SELECT_LEX *sl= thd->lex.current_select->outer_select();
......@@ -940,6 +987,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
*/
if ((ref= find_item_in_list(this,
*(thd->lex.current_select->get_item_list()),
&counter,
((sl &&
thd->lex.current_select->linkage !=
DERIVED_TABLE_TYPE) ?
......@@ -961,6 +1009,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
for ( ; sl ; sl= sl->outer_select())
{
if ((ref= find_item_in_list(this, (last= sl)->item_list,
&counter,
REPORT_EXCEPT_NOT_FOUND)) !=
(Item **)not_found_item)
break;
......@@ -980,6 +1029,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
// Call to report error
find_item_in_list(this,
*(thd->lex.current_select->get_item_list()),
&counter,
REPORT_ALL_ERRORS);
ref= 0;
return 1;
......@@ -996,17 +1046,35 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
}
else
{
depended_from= last;
if (!(*ref)->fixed)
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
"forward reference in item list");
return -1;
}
ref= (depended_from= last)->ref_pointer_array + counter-1;
thd->lex.current_select->mark_as_dependent(last);
thd->add_possible_loop(this);
}
}
else if (!ref)
return 1;
else
{
if (!(*ref)->fixed)
{
my_error(ER_ILLEGAL_REFERENCE, MYF(0), name,
"forward reference in item list");
return -1;
}
ref= thd->lex.current_select->ref_pointer_array + counter-1;
}
max_length= (*ref)->max_length;
maybe_null= (*ref)->maybe_null;
decimals= (*ref)->decimals;
}
if (((*ref)->with_sum_func &&
(depended_from ||
!(thd->lex.current_select->linkage != GLOBAL_OPTIONS_TYPE &&
......
......@@ -50,6 +50,8 @@ class Item {
// alloc & destruct is done as start of select using sql_alloc
Item();
// copy constructor used by Item_field, Item_ref & agregate (sum) functions
Item(Item &item);
virtual ~Item() { name=0; } /*lint -e1509 */
void set_name(const char *str,uint length=0);
void init_make_field(Send_field *tmp_field,enum enum_field_types type);
......@@ -67,7 +69,8 @@ class Item {
virtual longlong val_int()=0;
virtual String *val_str(String*)=0;
virtual void make_field(Send_field *field)=0;
virtual Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return 0; }
virtual Field *tmp_table_field() { return 0; }
virtual Field *tmp_table_field(TABLE *t_arg) { return 0; }
virtual const char *full_name() const { return name ? name : "???"; }
virtual double val_result() { return val(); }
virtual longlong val_int_result() { return val_int(); }
......@@ -82,12 +85,14 @@ class Item {
virtual bool const_item() const { return used_tables() == 0; }
virtual void print(String *str_arg) { str_arg->append(full_name()); }
virtual void update_used_tables() {}
virtual void split_sum_func(List<Item> &fields) {}
virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields) {}
virtual bool get_date(TIME *ltime,bool fuzzydate);
virtual bool get_time(TIME *ltime);
virtual bool is_null() { return 0; };
virtual bool check_loop(uint id);
virtual void top_level_item() {}
virtual Item * get_same() { return this; }
virtual Item * get_tmp_table_item() { return get_same(); }
virtual bool binary() const
{ return str_value.charset()->state & MY_CS_BINSORT ? 1 : 0 ; }
......@@ -159,11 +164,14 @@ class Item_ident :public Item
const char *table_name;
const char *field_name;
st_select_lex *depended_from;
Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par)
:db_name(db_name_par),table_name(table_name_par),
field_name(field_name_par), depended_from(0)
{ name = (char*) field_name_par; }
// copy constructor used by Item_field & Item_ref
Item_ident(Item_ident &item);
const char *full_name() const;
};
......@@ -179,6 +187,8 @@ class Item_field :public Item_ident
const char *field_name_par)
:Item_ident(db_par,table_name_par,field_name_par),field(0),result_field(0)
{}
// copy constructor need to process subselect with temporary tables
Item_field(Item_field &item);
Item_field(Field *field);
enum Type type() const { return FIELD_ITEM; }
bool eq(const Item *item, bool binary_cmp) const;
......@@ -202,10 +212,12 @@ class Item_field :public Item_ident
{
return field->result_type();
}
Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; }
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg) { return result_field; }
bool get_date(TIME *ltime,bool fuzzydate);
bool get_time(TIME *ltime);
bool is_null() { return field->is_null(); }
Item * get_tmp_table_item();
};
......@@ -448,8 +460,13 @@ class Item_result_field :public Item /* Item with result field */
public:
Field *result_field; /* Save result here */
Item_result_field() :result_field(0) {}
Item_result_field(Item_result_field &item): Item(item)
{
result_field= item.result_field;
}
~Item_result_field() {} /* Required with gcc 2.95 */
Field *tmp_table_field(TABLE *t_arg=(TABLE *)0) { return result_field; }
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg) { return result_field; }
table_map used_tables() const { return 1; }
virtual void fix_length_and_dec()=0;
};
......@@ -463,6 +480,8 @@ class Item_ref :public Item_ident
:Item_ident(db_par,table_name_par,field_name_par),ref(0) {}
Item_ref(Item **item, char *table_name_par,char *field_name_par)
:Item_ident(NullS,table_name_par,field_name_par),ref(item) {}
// copy constructor need to process subselect with temporary tables
Item_ref(Item_ref &item): Item_ident(item), ref(item.ref) {}
enum Type type() const { return REF_ITEM; }
bool eq(const Item *item, bool binary_cmp) const
{ return ref && (*ref)->eq(item, binary_cmp); }
......
......@@ -1175,16 +1175,20 @@ void Item_func_in::update_used_tables()
const_item_cache&=item->const_item();
}
void Item_func_in::split_sum_func(List<Item> &fields)
void Item_func_in::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
{
if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
item->split_sum_func(fields);
item->split_sum_func(ref_pointer_array, fields);
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
uint el= fields.elements;
fields.push_front(item);
item=new Item_ref((Item**) fields.head_ref(),0,item->name);
ref_pointer_array[el]= item;
item=new Item_ref(ref_pointer_array + el,
0, item->name);
}
Item_func::split_sum_func(fields);
Item_func::split_sum_func(ref_pointer_array, fields);
}
......@@ -1281,7 +1285,7 @@ bool Item_cond::check_loop(uint id)
DBUG_RETURN(0);
}
void Item_cond::split_sum_func(List<Item> &fields)
void Item_cond::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
{
List_iterator<Item> li(list);
Item *item;
......@@ -1290,11 +1294,13 @@ void Item_cond::split_sum_func(List<Item> &fields)
while ((item=li++))
{
if (item->with_sum_func && item->type() != SUM_FUNC_ITEM)
item->split_sum_func(fields);
item->split_sum_func(ref_pointer_array, fields);
else if (item->used_tables() || item->type() == SUM_FUNC_ITEM)
{
uint el= fields.elements;
fields.push_front(item);
li.replace(new Item_ref((Item**) fields.head_ref(),0,item->name));
ref_pointer_array[el]= item;
li.replace(new Item_ref(ref_pointer_array + el, 0, item->name));
}
item->update_used_tables();
used_tables_cache|=item->used_tables();
......
......@@ -509,7 +509,7 @@ class Item_func_in :public Item_int_func
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
void update_used_tables();
void split_sum_func(List<Item> &fields);
void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
bool check_loop(uint id)
{
DBUG_ENTER("Item_func_in::check_loop");
......@@ -656,7 +656,7 @@ class Item_cond :public Item_bool_func
table_map used_tables() const;
void update_used_tables();
void print(String *str);
void split_sum_func(List<Item> &fields);
void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
bool check_loop(uint id);
void top_level_item() { abort_on_null=1; }
......
......@@ -146,17 +146,19 @@ bool Item_func::check_loop(uint id)
DBUG_RETURN(0);
}
void Item_func::split_sum_func(List<Item> &fields)
void Item_func::split_sum_func(Item **ref_pointer_array, List<Item> &fields)
{
Item **arg,**arg_end;
for (arg=args, arg_end=args+arg_count; arg != arg_end ; arg++)
{
if ((*arg)->with_sum_func && (*arg)->type() != SUM_FUNC_ITEM)
(*arg)->split_sum_func(fields);
(*arg)->split_sum_func(ref_pointer_array, fields);
else if ((*arg)->used_tables() || (*arg)->type() == SUM_FUNC_ITEM)
{
uint el= fields.elements;
fields.push_front(*arg);
*arg=new Item_ref((Item**) fields.head_ref(),0,(*arg)->name);
ref_pointer_array[el]= *arg;
*arg=new Item_ref(ref_pointer_array + el, 0, (*arg)->name);
}
}
}
......@@ -225,14 +227,11 @@ bool Item_func::eq(const Item *item, bool binary_cmp) const
return 1;
}
Field *Item_func::tmp_table_field(TABLE *t_arg)
{
Field *res;
LINT_INIT(res);
if (!t_arg)
return result_field;
switch (result_type()) {
case INT_RESULT:
if (max_length > 11)
......@@ -303,6 +302,16 @@ void Item_func::fix_num_length_and_dec()
max_length=float_length(decimals);
}
Item * Item_func::get_tmp_table_item()
{
if (!with_sum_func && !const_item())
{
return new Item_field(result_field);
}
else
return get_same();
}
String *Item_int_func::val_str(String *str)
{
longlong nr=val_int();
......
......@@ -118,7 +118,7 @@ class Item_func :public Item_result_field
inline Item **arguments() const { return args; }
inline uint argument_count() const { return arg_count; }
inline void remove_arguments() { arg_count=0; }
virtual void split_sum_func(List<Item> &fields);
virtual void split_sum_func(Item **ref_pointer_array, List<Item> &fields);
void print(String *str);
void print_op(String *str);
void fix_num_length_and_dec();
......@@ -132,8 +132,10 @@ class Item_func :public Item_result_field
}
bool is_null() { (void) val_int(); return null_value; }
friend class udf_handler;
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg);
bool check_loop(uint id);
Item * get_tmp_table_item();
};
......
......@@ -288,6 +288,8 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex,
compare_func_creator func)
{
DBUG_ENTER("Item_in_subselect::single_value_transformer");
THD *thd= current_thd;
for (SELECT_LEX * sl= select_lex; sl; sl= sl->next_select())
{
Item *item;
......@@ -301,11 +303,15 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex,
Item *expr= new Item_outer_select_context_saver(left_expr);
if (sl->having || sl->with_sum_func || sl->group_list.first ||
sl->order_list.first)
if (sl->having || sl->with_sum_func || sl->group_list.elements ||
sl->order_list.elements)
{
sl->item_list.push_back(item);
item= (*func)(expr, new Item_ref(sl->item_list.head_ref(),
setup_ref_array(thd, &sl->ref_pointer_array,
1+ select_lex->with_sum_func +
select_lex->order_list.elements +
select_lex->group_list.elements);
item= (*func)(expr, new Item_ref(sl->ref_pointer_array,
0, (char*)"<result>"));
if (sl->having || sl->with_sum_func || sl->group_list.first)
if (sl->having)
......@@ -348,7 +354,6 @@ void Item_in_subselect::single_value_transformer(st_select_lex *select_lex,
// it is single select without tables => possible optimization
item= (*func)(left_expr, item);
substitution= item;
THD *thd= current_thd;
if (thd->lex.describe)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
......@@ -424,8 +429,12 @@ int subselect_single_select_engine::prepare()
prepared= 1;
SELECT_LEX_NODE *save_select= thd->lex.current_select;
thd->lex.current_select= select_lex;
if(join->prepare((TABLE_LIST*) select_lex->table_list.first,
if(join->prepare(&select_lex->ref_pointer_array,
(TABLE_LIST*) select_lex->table_list.first,
select_lex->with_wild,
select_lex->where,
select_lex->order_list.elements +
select_lex->group_list.elements,
(ORDER*) select_lex->order_list.first,
(ORDER*) select_lex->group_list.first,
select_lex->having,
......
......@@ -41,9 +41,22 @@ Item_sum::Item_sum(List<Item> &list)
list.empty(); // Fields are used
}
Item_sum::Item_sum(Item_sum &item):
Item_result_field(item), quick_group(item.quick_group)
{
arg_count= item.arg_count;
if (arg_count <= 2)
args=tmp_args;
else
if (!(args=(Item**) sql_alloc(sizeof(Item*)*arg_count)))
return;
for(uint i= 0; i < arg_count; i++)
args[i]= item.args[i];
}
void Item_sum::mark_as_sum_func()
{
current_thd->lex.current_select->with_sum_func=1;
current_thd->lex.current_select->with_sum_func++;
with_sum_func= 1;
}
......@@ -90,6 +103,26 @@ void Item_sum::fix_num_length_and_dec()
max_length=float_length(decimals);
}
Item * Item_sum::get_tmp_table_item()
{
Item_sum* sum_item= (Item_sum *) get_same();
if (sum_item && sum_item->result_field) // If not a const sum func
{
Field *result_field= sum_item->result_field;
for (uint i=0 ; i < sum_item->arg_count ; i++)
{
Item *arg= sum_item->args[i];
if (!arg->const_item())
{
if (arg->type() == Item::FIELD_ITEM)
((Item_field*) arg)->field= result_field++;
else
sum_item->args[i]= new Item_field(result_field++);
}
}
}
return sum_item;
}
String *
Item_sum_num::val_str(String *str)
......@@ -933,7 +966,7 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)),
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);
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 &&
......@@ -946,11 +979,14 @@ int dump_leaf(byte* key, uint32 count __attribute__((unused)),
Item_sum_count_distinct::~Item_sum_count_distinct()
{
if (!original)
{
if (table)
free_tmp_table(current_thd, table);
delete tmp_table_param;
if (use_tree)
delete_tree(&tree);
delete_tree(tree);
}
}
......@@ -1072,7 +1108,7 @@ bool Item_sum_count_distinct::setup(THD *thd)
}
}
init_tree(&tree, min(thd->variables.max_heap_table_size,
init_tree(tree, min(thd->variables.max_heap_table_size,
thd->variables.sortbuff_size/16), 0,
key_length, compare_key, 0, NULL, cmp_arg);
use_tree = 1;
......@@ -1085,6 +1121,12 @@ bool Item_sum_count_distinct::setup(THD *thd)
*/
max_elements_in_tree = ((key_length) ?
thd->variables.max_heap_table_size/key_length : 1);
}
if (original)
{
original->table= table;
original->use_tree= use_tree;
}
return 0;
}
......@@ -1094,10 +1136,10 @@ int Item_sum_count_distinct::tree_to_myisam()
{
if (create_myisam_from_heap(current_thd, table, tmp_table_param,
HA_ERR_RECORD_FILE_FULL, 1) ||
tree_walk(&tree, (tree_walk_action)&dump_leaf, (void*)this,
tree_walk(tree, (tree_walk_action)&dump_leaf, (void*)this,
left_root_right))
return 1;
delete_tree(&tree);
delete_tree(tree);
use_tree = 0;
return 0;
}
......@@ -1105,7 +1147,7 @@ int Item_sum_count_distinct::tree_to_myisam()
void Item_sum_count_distinct::reset()
{
if (use_tree)
reset_tree(&tree);
reset_tree(tree);
else if (table)
{
table->file->extra(HA_EXTRA_NO_CACHE);
......@@ -1133,13 +1175,13 @@ bool Item_sum_count_distinct::add()
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->elements_in_tree > max_elements_in_tree)
{
if (tree_to_myisam())
return 1;
}
else if (!tree_insert(&tree, table->record[0] + rec_offset, 0,
tree.custom_arg))
else if (!tree_insert(tree, table->record[0] + rec_offset, 0,
tree->custom_arg))
return 1;
}
else if ((error=table->file->write_row(table->record[0])))
......@@ -1161,7 +1203,7 @@ longlong Item_sum_count_distinct::val_int()
if (!table) // Empty query
return LL(0);
if (use_tree)
return tree.elements_in_tree;
return tree->elements_in_tree;
table->file->info(HA_STATUS_VARIABLE | HA_STATUS_NO_LOCK);
return table->file->records;
}
......
This diff is collapsed.
......@@ -330,9 +330,10 @@ class Item_date :public Item_func
{
init_make_field(tmp_field,FIELD_TYPE_DATE);
}
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field : new Field_date(maybe_null, name, t_arg, thd_charset());
return (new Field_date(maybe_null, name, t_arg, thd_charset()));
}
};
......@@ -347,10 +348,10 @@ class Item_date_func :public Item_str_func
{
init_make_field(tmp_field,FIELD_TYPE_DATETIME);
}
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field : new Field_datetime(maybe_null, name,
t_arg, thd_charset());
return (new Field_datetime(maybe_null, name, t_arg, thd_charset()));
}
};
......@@ -373,10 +374,10 @@ class Item_func_curtime :public Item_func
{
init_make_field(tmp_field,FIELD_TYPE_TIME);
}
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field :
new Field_time(maybe_null, name, t_arg, thd_charset());
return (new Field_time(maybe_null, name, t_arg, thd_charset()));
}
};
......@@ -475,10 +476,10 @@ class Item_func_sec_to_time :public Item_str_func
{
init_make_field(tmp_field,FIELD_TYPE_TIME);
}
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field :
new Field_time(maybe_null, name, t_arg, thd_charset());
return (new Field_time(maybe_null, name, t_arg, thd_charset()));
}
};
......@@ -570,10 +571,10 @@ class Item_date_typecast :public Item_typecast
{
init_make_field(tmp_field,FIELD_TYPE_DATE);
}
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field :
new Field_date(maybe_null, name, t_arg, thd_charset());
return (new Field_date(maybe_null, name, t_arg, thd_charset()));
}
};
......@@ -587,10 +588,10 @@ class Item_time_typecast :public Item_typecast
{
init_make_field(tmp_field,FIELD_TYPE_TIME);
}
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field :
new Field_time(maybe_null, name, t_arg, thd_charset());
return (new Field_time(maybe_null, name, t_arg, thd_charset()));
}
};
......@@ -604,9 +605,9 @@ class Item_datetime_typecast :public Item_typecast
{
init_make_field(tmp_field,FIELD_TYPE_DATETIME);
}
Field *tmp_table_field() { return result_field; }
Field *tmp_table_field(TABLE *t_arg)
{
return (!t_arg) ? result_field : new Field_datetime(maybe_null, name,
t_arg, thd_charset());
return (new Field_datetime(maybe_null, name, t_arg, thd_charset()));
}
};
......@@ -37,6 +37,7 @@ class Item_sum_unique_users :public Item_sum_num
public:
Item_sum_unique_users(Item *name_arg,int start,int end,Item *item_arg)
:Item_sum_num(item_arg) {}
Item_sum_unique_users(Item_sum_unique_users &item): Item_sum_num(item) {}
double val() { return 0.0; }
enum Sumfunctype sum_func () const {return UNIQUE_USERS_FUNC;}
void reset() {}
......@@ -48,4 +49,5 @@ class Item_sum_unique_users :public Item_sum_num
fixed= 1;
return 0;
}
Item_sum * get_same() { return new Item_sum_unique_users(*this); }
};
......@@ -402,18 +402,21 @@ bool net_store_data(String *packet,CONVERT *convert, const char *from,
bool net_store_data(String *packet, CONVERT *convert, const char *from);
SORT_FIELD * make_unireg_sortorder(ORDER *order, uint *length);
int setup_order(THD *thd,TABLE_LIST *tables, List<Item> &fields,
List <Item> &all_fields, ORDER *order);
int setup_group(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &all_fields, ORDER *order,
int setup_ref_array(THD *thd, Item ***rref_pointer_array, uint elements);
int setup_order(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List <Item> &all_fields, ORDER *order);
int setup_group(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, List<Item> &all_fields, ORDER *order,
bool *hidden_group_fields);
int handle_select(THD *thd, LEX *lex, select_result *result);
int mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &list,COND *conds,
ORDER *order, ORDER *group,Item *having,ORDER *proc_param,
ulong select_type,select_result *result,
SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex,
bool fake_select_lex);
int mysql_select(THD *thd, Item ***rref_pointer_array,
TABLE_LIST *tables, uint wild_num, List<Item> &list,
COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, ulong select_type,
select_result *result, SELECT_LEX_UNIT *unit,
SELECT_LEX *select_lex, bool fake_select_lex);
void free_ulderlayed_joins(THD *thd, SELECT_LEX *select);
void fix_tables_pointers(SELECT_LEX *select_lex);
int mysql_explain_union(THD *thd, SELECT_LEX_UNIT *unit,
select_result *result);
......@@ -440,7 +443,7 @@ int mysql_alter_table(THD *thd, char *new_db, char *new_name,
List<create_field> &fields,
List<Key> &keys,List<Alter_drop> &drop_list,
List<Alter_column> &alter_list,
ORDER *order,
uint order_num, ORDER *order,
bool drop_primary,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff=LEAVE_AS_IS,
......@@ -456,7 +459,7 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list,
List<Alter_drop> &drop_list);
int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields,
List<Item> &values,COND *conds,
ORDER *order, ha_rows limit,
uint order_num, ORDER *order, ha_rows limit,
enum enum_duplicates handle_duplicates);
int mysql_multi_update(THD *thd, TABLE_LIST *table_list,
List<Item> *fields, List<Item> *values,
......@@ -575,15 +578,17 @@ SQL_SELECT *make_select(TABLE *head, table_map const_tables,
enum find_item_error_report_type {REPORT_ALL_ERRORS, REPORT_EXCEPT_NOT_FOUND,
IGNORE_ERRORS};
extern const Item **not_found_item;
Item ** find_item_in_list(Item *item, List<Item> &items,
Item ** find_item_in_list(Item *item, List<Item> &items, uint *counter,
find_item_error_report_type report_error);
bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name,
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 allow_sum_func);
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list, uint wild_num);
int setup_fields(THD *thd, Item** ref_pointer_array, TABLE_LIST *tables,
List<Item> &item, 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(SELECT_LEX* select);
int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order);
......
......@@ -2013,10 +2013,14 @@ const Item **not_found_item= (const Item**) 0x1;
/*
Find Item in list of items (find_field_in_tables analog)
TODO
is it better return only counter?
SYNOPSIS
find_item_in_list()
find - item to find
items - list of items
counter - to return number of found item
report_error
REPORT_ALL_ERRORS - report errors, return 0 if error
REPORT_EXCEPT_NOT_FOUND - do not report 'not found' error and return not_ found_item, report other errors, return 0
......@@ -2033,7 +2037,7 @@ const Item **not_found_item= (const Item**) 0x1;
*/
Item **
find_item_in_list(Item *find, List<Item> &items,
find_item_in_list(Item *find, List<Item> &items, uint *counter,
find_item_error_report_type report_error)
{
List_iterator<Item> li(items);
......@@ -2046,8 +2050,10 @@ find_item_in_list(Item *find, List<Item> &items,
table_name= ((Item_ident*) find)->table_name;
}
uint i= 0;
while ((item=li++))
{
i++;
if (field_name && item->type() == Item::FIELD_ITEM)
{
if (!my_strcasecmp(system_charset_info,
......@@ -2064,11 +2070,13 @@ find_item_in_list(Item *find, List<Item> &items,
find->full_name(), current_thd->where);
return (Item**) 0;
}
found=li.ref();
found= li.ref();
*counter= i;
}
else if (!strcmp(((Item_field*) item)->table_name,table_name))
{
found=li.ref();
found= li.ref();
*counter= i;
break;
}
}
......@@ -2078,7 +2086,8 @@ find_item_in_list(Item *find, List<Item> &items,
!my_strcasecmp(system_charset_info,
item->name,find->name)))
{
found=li.ref();
found= li.ref();
*counter= i;
break;
}
}
......@@ -2096,22 +2105,18 @@ find_item_in_list(Item *find, List<Item> &items,
}
/****************************************************************************
** Check that all given fields exists and fill struct with current data
** Expand all '*' in given fields
****************************************************************************/
int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
bool set_query_id, List<Item> *sum_func_list,
bool allow_sum_func)
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list,
uint wild_num)
{
if (!wild_num)
return 0;
reg2 Item *item;
List_iterator<Item> it(fields);
DBUG_ENTER("setup_fields");
thd->set_query_id=set_query_id;
thd->allow_sum_func= allow_sum_func;
thd->where="field list";
while ((item=it++))
while ( wild_num && (item= it++))
{
if (item->type() == Item::FIELD_ITEM && ((Item_field*) item)->field_name &&
((Item_field*) item)->field_name[0] == '*')
......@@ -2119,7 +2124,7 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
uint elem= fields.elements;
if (insert_fields(thd,tables,((Item_field*) item)->db_name,
((Item_field*) item)->table_name, &it))
DBUG_RETURN(-1); /* purecov: inspected */
return (-1);
if (sum_func_list)
{
/*
......@@ -2129,23 +2134,44 @@ int setup_fields(THD *thd, TABLE_LIST *tables, List<Item> &fields,
*/
sum_func_list->elements+= fields.elements - elem;
}
wild_num--;
}
else
}
return 0;
}
/****************************************************************************
** Check that all given fields exists and fill struct with current data
****************************************************************************/
int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
List<Item> &fields, 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= allow_sum_func;
thd->where="field list";
for (uint i= 0; (item= it++); i++)
{
if (item->check_cols(1) ||
item->fix_fields(thd, tables, it.ref()))
DBUG_RETURN(-1); /* purecov: inspected */
item= *(it.ref()); //Item can be chenged in fix fields
if (ref_pointer_array)
ref_pointer_array[i]= item;
if (item->with_sum_func && item->type() != Item::SUM_FUNC_ITEM &&
sum_func_list)
item->split_sum_func(*sum_func_list);
item->split_sum_func(ref_pointer_array, *sum_func_list);
thd->used_tables|=item->used_tables();
}
}
DBUG_RETURN(test(thd->fatal_error || thd->net.report_error));
}
/*
Remap table numbers if INSERT ... SELECT
Check also that the 'used keys' and 'ignored keys' exists and set up the
......@@ -2459,7 +2485,7 @@ int mysql_create_index(THD *thd, TABLE_LIST *table_list, List<Key> &keys)
create_info.table_charset=default_charset_info;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
fields, keys, drop, alter, (ORDER*)0, FALSE,
fields, keys, drop, alter, 0, (ORDER*)0, FALSE,
DUP_ERROR));
}
......@@ -2476,7 +2502,7 @@ int mysql_drop_index(THD *thd, TABLE_LIST *table_list, List<Alter_drop> &drop)
create_info.table_charset=default_charset_info;
DBUG_RETURN(mysql_alter_table(thd,table_list->db,table_list->real_name,
&create_info, table_list,
fields, keys, drop, alter, (ORDER*)0, FALSE,
fields, keys, drop, alter, 0, (ORDER*)0, FALSE,
DUP_ERROR));
}
......
......@@ -376,7 +376,7 @@ struct system_variables
CONVERT *convert_set;
};
void free_tmp_table(THD *thd, TABLE *entry);
/*
For each client connection we create a separate thread with THD serving as
a thread/connection descriptor
......@@ -486,6 +486,7 @@ class THD :public ilink {
CHARSET_INFO *db_charset;
CHARSET_INFO *thd_charset;
List<Item> *possible_loops; // Items that may cause loops in subselects
List<TABLE> temporary_tables_should_be_free; // list of temporary tables
List <MYSQL_ERROR> warn_list;
uint warn_count[(uint) MYSQL_ERROR::WARN_LEVEL_END];
uint total_warn_count, old_total_warn_count;
......@@ -640,6 +641,17 @@ class THD :public ilink {
net.report_error= 0;
}
void add_possible_loop(Item *);
void free_tmp_tables()
{
if (temporary_tables_should_be_free.elements)
{
List_iterator_fast<TABLE> lt(temporary_tables_should_be_free);
TABLE *table;
while ((table= lt++))
free_tmp_table(this,table);
temporary_tables_should_be_free.empty();
}
}
};
/*
......
......@@ -92,6 +92,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
if ((select && select->check_quick(safe_update, limit)) || !limit)
{
delete select;
free_ulderlayed_joins(thd, &thd->lex.select_lex);
send_ok(thd,0L);
DBUG_RETURN(0); // Nothing to delete
}
......@@ -103,6 +104,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
if (safe_update && !using_limit)
{
delete select;
free_ulderlayed_joins(thd, &thd->lex.select_lex);
send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
DBUG_RETURN(1);
}
......@@ -124,7 +126,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
if (setup_order(thd, &tables, fields, all_fields, order) ||
if (setup_order(thd, 0, &tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
(table->found_records = filesort(thd, table, sortorder, length,
(SQL_SELECT *) 0, HA_POS_ERROR,
......@@ -132,6 +134,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
== HA_POS_ERROR)
{
delete select;
free_ulderlayed_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1); // This will force out message
}
}
......@@ -207,6 +210,7 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, ORDER *order,
thd->lock=0;
}
delete select;
free_ulderlayed_joins(thd, &thd->lex.select_lex);
if (error >= 0 || thd->net.report_error)
send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN: 0);
else
......
......@@ -58,7 +58,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
if (!(res=open_and_lock_tables(thd,tables)))
{
if (setup_fields(thd,tables,item_list,0,0,1))
if (setup_wild(thd, tables, item_list, 0, sl->with_wild) ||
setup_fields(thd, 0, tables, item_list, 0, 0, 1))
{
res=-1;
goto exit;
......@@ -87,9 +88,11 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
SELECT_LEX_NODE *save_current_select= lex->current_select;
lex->current_select= sl;
res= mysql_select(thd, tables, sl->item_list,
sl->where, (ORDER *) sl->order_list.first,
(ORDER*) sl->group_list.first,
res= mysql_select(thd, &sl->ref_pointer_array, tables, sl->with_wild,
sl->item_list, sl->where,
sl->order_list.elements+sl->group_list.elements,
(ORDER *) sl->order_list.first,
(ORDER *) sl->group_list.first,
sl->having, (ORDER*) NULL,
sl->options | thd->options | SELECT_NO_UNLOCK,
derived_result, unit, sl, 0);
......@@ -122,6 +125,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
}
if (res)
free_tmp_table(thd,table);
else
thd->temporary_tables_should_be_free.push_front(table);
exit:
close_thread_tables(thd);
}
......
......@@ -25,7 +25,7 @@ int mysql_do(THD *thd, List<Item> &values)
List_iterator<Item> li(values);
Item *value;
DBUG_ENTER("mysql_do");
if (setup_fields(thd,0, values, 0, 0, 0))
if (setup_fields(thd, 0, 0, values, 0, 0, 0))
DBUG_RETURN(-1);
while ((value = li++))
value->val_int();
......
......@@ -81,7 +81,7 @@ check_insert_fields(THD *thd,TABLE *table,List<Item> &fields,
thd->dupp_field=0;
if (setup_tables(&table_list) ||
setup_fields(thd,&table_list,fields,1,0,0))
setup_fields(thd, 0, &table_list,fields,1,0,0))
return -1;
if (thd->dupp_field)
{
......@@ -171,10 +171,10 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
values= its++;
if (check_insert_fields(thd,table,fields,*values,1) ||
setup_tables(insert_table_list) ||
setup_fields(thd, insert_table_list, *values, 0, 0, 0) ||
setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0) ||
(duplic == DUP_UPDATE &&
(setup_fields(thd, insert_table_list, update_fields, 0, 0, 0) ||
setup_fields(thd, insert_table_list, update_values, 0, 0, 0))))
(setup_fields(thd, 0, insert_table_list, update_fields, 0, 0, 0) ||
setup_fields(thd, 0, insert_table_list, update_values, 0, 0, 0))))
goto abort;
if (find_real_table_in_list(table_list->next,
table_list->db, table_list->real_name))
......@@ -194,7 +194,7 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
MYF(0),counter);
goto abort;
}
if (setup_fields(thd,insert_table_list,*values,0,0,0))
if (setup_fields(thd, 0, insert_table_list, *values, 0, 0, 0))
goto abort;
}
its.rewind ();
......@@ -381,11 +381,13 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
thd->cuted_fields);
::send_ok(thd,info.copied+info.deleted,(ulonglong)id,buff);
}
free_ulderlayed_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(0);
abort:
if (lock_type == TL_WRITE_DELAYED)
end_delayed_insert(thd);
free_ulderlayed_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1);
}
......
......@@ -944,6 +944,7 @@ void st_select_lex_node::init_query()
next= master= slave= link_next= 0;
prev= link_prev= 0;
dependent= 0;
ref_pointer_array= 0;
}
void st_select_lex_node::init_select()
......@@ -967,6 +968,8 @@ void st_select_lex_unit::init_query()
union_option= 0;
prepared= optimized= executed= 0;
item= 0;
union_result= 0;
table= 0;
}
void st_select_lex::init_query()
......@@ -979,6 +982,7 @@ void st_select_lex::init_query()
join= 0;
olap= UNSPECIFIED_OLAP_TYPE;
having_fix_field= 0;
with_wild= 0;
}
void st_select_lex::init_select()
......@@ -1110,7 +1114,7 @@ bool st_select_lex_node::add_group_to_list(THD *thd, Item *item, bool asc)
bool st_select_lex_node::add_order_to_list(THD *thd, Item *item, bool asc)
{
return add_to_list(thd, order_list,item,asc);
return add_to_list(thd, order_list, item, asc);
}
bool st_select_lex_node::add_ftfunc_to_list(Item_func_match *func)
......
......@@ -208,7 +208,10 @@ class st_select_lex_node {
List<List_item> expr_list;
List<List_item> when_list; /* WHEN clause (expression) */
ha_rows select_limit, offset_limit; /* LIMIT clause parameters */
bool with_sum_func;
// Arrays of pointers to top elements of all_fields list
Item **ref_pointer_array;
uint with_sum_func; /* sum function indicator and number of it */
bool create_refs;
bool dependent; /* dependent from outer select subselect */
......@@ -269,11 +272,10 @@ class select_union;
class st_select_lex_unit: public st_select_lex_node {
protected:
List<Item> item_list;
List<JOIN*> joins; /* list of *JOINs, to delete it in cleanup() */
TABLE_LIST result_table_list;
select_union *union_result;
TABLE *table; /* temporary table using for appending UNION results */
THD *thd;
select_result *result;
int res;
bool describe, found_rows_for_union,
......@@ -290,6 +292,8 @@ class st_select_lex_unit: public st_select_lex_node {
ha_rows select_limit_cnt, offset_limit_cnt;
/* not NULL if union used in subselect, point to subselect item */
Item_subselect *item;
THD *thd;
uint union_option;
void init_query();
......@@ -336,6 +340,7 @@ class st_select_lex: public st_select_lex_node
const char *type; /* type of select for EXPLAIN */
uint in_sum_expr;
uint select_number; /* number of select (used for EXPLAIN) */
uint with_wild; /* item list contain '*' */
bool braces; /* SELECT ... UNION (SELECT ... ) <- this braces */
/* TRUE when having fix field called in processing of this SELECT */
bool having_fix_field;
......
......@@ -147,12 +147,20 @@ class base_list :public Sql_alloc {
class base_list_iterator
{
protected:
base_list *list;
list_node **el,**prev,*current;
void sublist(base_list &ls, uint elm)
{
ls.first= *el;
ls.last= list->last;
ls.elements= elm;
}
public:
base_list_iterator(base_list &list_par) :list(&list_par),el(&list_par.first),
prev(0),current(0)
base_list_iterator(base_list &list_par)
:list(&list_par), el(&list_par.first), prev(0), current(0)
{}
inline void *next(void)
{
prev=el;
......@@ -212,7 +220,6 @@ class base_list_iterator
friend class error_list_iterator;
};
template <class T> class List :public base_list
{
public:
......@@ -260,6 +267,10 @@ template <class T> class List_iterator_fast :public base_list_iterator
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(); }
void sublist(List<T> &list, uint el)
{
base_list_iterator::sublist(list, el);
}
};
......
......@@ -117,7 +117,8 @@ 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,0))
if (setup_tables(table_list) ||
setup_fields(thd, 0, table_list, fields, 1, 0, 0))
DBUG_RETURN(-1);
if (thd->dupp_field)
{
......
......@@ -164,8 +164,10 @@ int handle_olaps(LEX *lex, SELECT_LEX *select_lex)
if (setup_tables((TABLE_LIST *)select_lex->table_list.first) ||
setup_fields(lex->thd,(TABLE_LIST *)select_lex->table_list.first,select_lex->item_list,1,&all_fields,1) ||
setup_fields(lex->thd,(TABLE_LIST *)select_lex->table_list.first,item_list_copy,1,&all_fields,1))
setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
select_lex->item_list, 1, &all_fields,1) ||
setup_fields(lex->thd, 0, (TABLE_LIST *)select_lex->table_list.first,
item_list_copy, 1, &all_fields, 1))
return -1;
if (select_lex->olap == CUBE_TYPE)
......
......@@ -1915,6 +1915,7 @@ mysql_execute_command(THD *thd)
&lex->create_info,
tables, lex->create_list,
lex->key_list, lex->drop_list, lex->alter_list,
select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
lex->drop_primary, lex->duplicates,
lex->alter_keys_onoff, lex->simple_alter);
......@@ -2026,8 +2027,8 @@ mysql_execute_command(THD *thd)
res= mysql_alter_table(thd, NullS, NullS, &create_info,
tables, lex->create_list,
lex->key_list, lex->drop_list, lex->alter_list,
(ORDER *) 0,
0,DUP_ERROR);
0, (ORDER *) 0,
0, DUP_ERROR);
}
else
res = mysql_optimize_table(thd, tables, &lex->check_opt);
......@@ -2047,6 +2048,7 @@ mysql_execute_command(THD *thd)
select_lex->item_list,
lex->value_list,
select_lex->where,
select_lex->order_list.elements,
(ORDER *) select_lex->order_list.first,
select_lex->select_limit,
lex->duplicates);
......@@ -2246,10 +2248,12 @@ mysql_execute_command(THD *thd)
if (!thd->fatal_error && (result= new multi_delete(thd,aux_tables,
table_count)))
{
res= mysql_select(thd,select_lex->get_table_list(),
res= mysql_select(thd, &select_lex->ref_pointer_array,
select_lex->get_table_list(),
select_lex->with_wild,
select_lex->item_list,
select_lex->where,
(ORDER *)NULL,(ORDER *)NULL,(Item *)NULL,
0, (ORDER *)NULL, (ORDER *)NULL, (Item *)NULL,
(ORDER *)NULL,
select_lex->options | thd->options |
SELECT_NO_JOIN_CACHE,
......@@ -2741,6 +2745,7 @@ mysql_execute_command(THD *thd)
send_ok(thd);
break;
}
thd->free_tmp_tables();
thd->proc_info="query end"; // QQ
if (res < 0)
send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0);
......@@ -2988,6 +2993,7 @@ mysql_init_query(THD *thd)
LEX *lex=&thd->lex;
lex->unit.init_query();
lex->unit.init_select();
lex->unit.thd= thd;
lex->select_lex.init_query();
lex->value_list.empty();
lex->param_list.empty();
......@@ -3044,6 +3050,7 @@ mysql_new_select(LEX *lex, bool move_down)
return 1;
unit->init_query();
unit->init_select();
unit->thd= lex->thd;
unit->include_down(lex->current_select);
select_lex->include_down(unit);
}
......
......@@ -365,7 +365,7 @@ static int check_prepare_fields(THD *thd,TABLE *table, List<Item> &fields,
thd->dupp_field=0;
if (setup_tables(&table_list) ||
setup_fields(thd,&table_list,fields,1,0,0))
setup_fields(thd, 0, &table_list, fields, 1, 0, 0))
return -1;
if (thd->dupp_field)
{
......@@ -446,8 +446,9 @@ static bool mysql_test_upd_fields(PREP_STMT *stmt, TABLE_LIST *table_list,
if (!(table = open_ltable(thd,table_list,table_list->lock_type)))
DBUG_RETURN(1);
if (setup_tables(table_list) || setup_fields(thd,table_list,fields,1,0,0) ||
setup_conds(thd,table_list,&conds))
if (setup_tables(table_list) ||
setup_fields(thd, 0, table_list, fields, 1, 0, 0) ||
setup_conds(thd, table_list, &conds))
DBUG_RETURN(1);
/*
......@@ -488,10 +489,11 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
thd->used_tables=0; // Updated by setup_fields
if (setup_tables(tables) ||
setup_fields(thd,tables,fields,1,&all_fields,1) ||
setup_fields(thd, 0, 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))
setup_order(thd, 0, tables, fields, all_fields, order) ||
setup_group(thd, 0, tables, fields, all_fields, group,
&hidden_group_fields))
DBUG_RETURN(1);
if (having)
......@@ -502,7 +504,7 @@ static bool mysql_test_select_fields(PREP_STMT *stmt, TABLE_LIST *tables,
|| thd->fatal_error)
DBUG_RETURN(1);
if (having->with_sum_func)
having->split_sum_func(all_fields);
having->split_sum_func(0, all_fields);
}
if (setup_ftfuncs(&thd->lex.select_lex))
DBUG_RETURN(1);
......
This diff is collapsed.
......@@ -119,8 +119,10 @@ class TMP_TABLE_PARAM :public Sql_alloc
{
public:
List<Item> copy_funcs;
List<Item> save_copy_funcs;
List_iterator_fast<Item> copy_funcs_it;
Copy_field *copy_field, *copy_field_end;
Copy_field *save_copy_field, *save_copy_field_end;
byte *group_buff;
Item_result_field **funcs;
MI_COLUMNDEF *recinfo,*start_recinfo;
......@@ -166,10 +168,13 @@ class JOIN :public Sql_alloc
List<Item> *fields;
List<Item_buff> group_fields;
TABLE *tmp_table;
// used to store 2 possible tmp table of SELECT
TABLE *exec_tmp_table1, *exec_tmp_table2;
THD *thd;
Item_sum **sum_funcs;
Procedure *procedure;
Item *having;
Item *tmp_having; // To store Having when processed tenporary table
uint select_options;
select_result *result;
TMP_TABLE_PARAM tmp_table_param;
......@@ -179,6 +184,8 @@ class JOIN :public Sql_alloc
// select that processed
SELECT_LEX *select_lex;
JOIN *tmp_join; // copy of this JOIN to be used with temporary tables
bool select_distinct, //Is select distinct?
no_order, simple_order, simple_group,
skip_sort_order, need_tmp,
......@@ -186,7 +193,11 @@ class JOIN :public Sql_alloc
buffer_result;
DYNAMIC_ARRAY keyuse;
Item::cond_result cond_value;
List<Item> all_fields;
List<Item> all_fields; // to store all fields that used in query
//Above list changed to use temporary table
List<Item> tmp_all_fields1, tmp_all_fields2, tmp_all_fields3;
//Part, shared with list above, emulate following list
List<Item> tmp_fields_list1, tmp_fields_list2, tmp_fields_list3;
List<Item> & fields_list; // hold field list passed to mysql_select
int error;
......@@ -194,11 +205,14 @@ class JOIN :public Sql_alloc
COND *conds; // ---"---
TABLE_LIST *tables_list; //hold 'tables' parameter of mysql_selec
SQL_SELECT *select; //created in optimisation phase
TABLE *exec_tmp_table; //used in 'exec' to hold temporary
Item **ref_pointer_array; //used pointer reference for this select
// Copy of above to be used with different lists
Item **items0, **items1, **items2, **items3;
uint ref_pointer_array_size; // size of above in bytes
const char *zero_result_cause; // not 0 if exec must return zero result
my_bool union_part; // this subselect is part of union
bool union_part; // this subselect is part of union
bool optimized; // flag to avoid double optimization in EXPLAIN
JOIN(THD *thd, List<Item> &fields,
ulong select_options, select_result *result):
......@@ -208,14 +222,16 @@ class JOIN :public Sql_alloc
sort_and_group(0), first_record(0),
do_send_rows(1),
send_records(0), found_records(0), examined_rows(0),
exec_tmp_table1(0), exec_tmp_table2(0),
thd(thd),
sum_funcs(0),
procedure(0),
having(0),
having(0), tmp_having(0),
select_options(select_options),
result(result),
lock(thd->lock),
select_lex(0), //for safety
tmp_join(0),
select_distinct(test(select_options & SELECT_DISTINCT)),
no_order(0), simple_order(0), simple_group(0), skip_sort_order(0),
need_tmp(0),
......@@ -226,8 +242,10 @@ class JOIN :public Sql_alloc
fields_list(fields),
error(0),
select(0),
exec_tmp_table(0),
zero_result_cause(0)
ref_pointer_array(0), items0(0), items1(0), items2(0), items3(0),
ref_pointer_array_size(0),
zero_result_cause(0),
optimized(0)
{
fields_list = fields;
bzero((char*) &keyuse,sizeof(keyuse));
......@@ -235,16 +253,23 @@ class JOIN :public Sql_alloc
tmp_table_param.end_write_records= HA_POS_ERROR;
}
int prepare(TABLE_LIST *tables,
COND *conds, ORDER *order, ORDER *group, Item *having,
ORDER *proc_param, SELECT_LEX *select, SELECT_LEX_UNIT *unit,
bool fake_select_lex);
int prepare(Item ***rref_pointer_array, TABLE_LIST *tables, uint wind_num,
COND *conds, uint og_num, ORDER *order, ORDER *group,
Item *having, ORDER *proc_param, SELECT_LEX *select,
SELECT_LEX_UNIT *unit, bool fake_select_lex);
int optimize();
int global_optimize();
int reinit();
void exec();
int cleanup(THD *thd);
bool check_loop(uint id);
void restore_tmp();
inline void init_items_ref_array()
{
items0= ref_pointer_array + all_fields.elements;
ref_pointer_array_size= all_fields.elements*sizeof(Item*);
memcpy(items0, ref_pointer_array, ref_pointer_array_size);
}
};
......@@ -263,7 +288,10 @@ TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
void free_tmp_table(THD *thd, TABLE *entry);
void count_field_types(TMP_TABLE_PARAM *param, List<Item> &fields,
bool reset_with_sum_func);
bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,List<Item> &fields);
bool setup_copy_fields(THD *thd, TMP_TABLE_PARAM *param,
Item **ref_pointer_array,
List<Item> &new_list1, List<Item> &new_list2,
uint elements, List<Item> &fields);
void copy_fields(TMP_TABLE_PARAM *param);
void copy_funcs(Item_result_field **func_ptr);
bool create_myisam_from_heap(THD *thd, TABLE *table, TMP_TABLE_PARAM *param,
......
......@@ -37,7 +37,7 @@ static char *make_unique_key_name(const char *field_name,KEY *start,KEY *end);
static int copy_data_between_tables(TABLE *from,TABLE *to,
List<create_field> &create,
enum enum_duplicates handle_duplicates,
ORDER *order,
uint order_num, ORDER *order,
ha_rows *copied,ha_rows *deleted);
/*****************************************************************************
......@@ -1415,7 +1415,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
List<create_field> &fields,
List<Key> &keys,List<Alter_drop> &drop_list,
List<Alter_column> &alter_list,
ORDER *order,
uint order_num, ORDER *order,
bool drop_primary,
enum enum_duplicates handle_duplicates,
enum enum_enable_or_disable keys_onoff,
......@@ -1877,7 +1877,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
if (!new_table->is_view)
error=copy_data_between_tables(table,new_table,create_list,
handle_duplicates,
order, &copied, &deleted);
order_num, order, &copied, &deleted);
thd->last_insert_id=next_insert_id; // Needed for correct log
thd->count_cuted_fields=0; // Don`t calc cuted fields
new_table->time_stamp=save_time_stamp;
......@@ -2090,7 +2090,7 @@ static int
copy_data_between_tables(TABLE *from,TABLE *to,
List<create_field> &create,
enum enum_duplicates handle_duplicates,
ORDER *order,
uint order_num, ORDER *order,
ha_rows *copied,
ha_rows *deleted)
{
......@@ -2138,7 +2138,10 @@ copy_data_between_tables(TABLE *from,TABLE *to,
tables.db = from->table_cache_key;
error=1;
if (setup_order(thd, &tables, fields, all_fields, order) ||
if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
order_num)||
setup_order(thd, thd->lex.select_lex.ref_pointer_array,
&tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
(from->found_records = filesort(thd, from, sortorder, length,
(SQL_SELECT *) 0, HA_POS_ERROR,
......
......@@ -108,7 +108,6 @@ bool select_union::flush()
return 0;
}
typedef JOIN * JOIN_P;
int st_select_lex_unit::prepare(THD *thd, select_result *result)
{
DBUG_ENTER("st_select_lex_unit::prepare");
......@@ -116,11 +115,9 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result)
if (prepared)
DBUG_RETURN(0);
prepared= 1;
union_result=0;
res= 0;
found_rows_for_union= 0;
TMP_TABLE_PARAM tmp_table_param;
this->thd= thd;
this->result= result;
SELECT_LEX_NODE *lex_select_save= thd->lex.current_select;
SELECT_LEX *sl;
......@@ -143,7 +140,9 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result)
while ((item= it++))
if (item_list.push_back(item))
goto err;
if (setup_fields(thd,first_table,item_list,0,0,1))
if (setup_wild(thd, first_table, item_list, 0,
first_select()->with_wild) ||
setup_fields(thd, 0, first_table, item_list, 0, 0, 1))
goto err;
}
......@@ -169,13 +168,11 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result)
union_result->tmp_table_param=&tmp_table_param;
// prepare selects
joins.empty();
for (sl= first_select(); sl; sl= sl->next_select())
{
JOIN *join= new JOIN(thd, sl->item_list,
sl->options | thd->options | SELECT_NO_UNLOCK,
union_result);
joins.push_back(new JOIN_P(join));
thd->lex.current_select= sl;
offset_limit_cnt= sl->offset_limit;
select_limit_cnt= sl->select_limit+sl->offset_limit;
......@@ -184,8 +181,11 @@ int st_select_lex_unit::prepare(THD *thd, select_result *result)
if (select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
res= join->prepare((TABLE_LIST*) sl->table_list.first,
res= join->prepare(&sl->ref_pointer_array,
(TABLE_LIST*) sl->table_list.first, sl->with_wild,
sl->where,
((sl->braces) ? sl->order_list.elements : 0) +
sl->group_list.elements,
(sl->braces) ?
(ORDER *)sl->order_list.first : (ORDER *) 0,
(ORDER*) sl->group_list.first,
......@@ -286,8 +286,9 @@ int st_select_lex_unit::exec()
select_limit_cnt= HA_POS_ERROR; // no limit
if (select_limit_cnt == HA_POS_ERROR)
thd->options&= ~OPTION_FOUND_ROWS;
res= mysql_select(thd,&result_table_list,
item_list, NULL,
res= mysql_select(thd, &ref_pointer_array, &result_table_list,
0, item_list, NULL,
global_parameters->order_list.elements,
(ORDER*)global_parameters->order_list.first,
(ORDER*) NULL, NULL, (ORDER*) NULL,
thd->options, result, this, first_select(), 1);
......@@ -303,20 +304,24 @@ int st_select_lex_unit::exec()
int st_select_lex_unit::cleanup()
{
DBUG_ENTER("st_select_lex_unit::cleanup");
int error= 0;
if (union_result)
{
delete union_result;
free_tmp_table(thd,table);
if (table)
free_tmp_table(thd, table);
table= 0; // Safety
}
List_iterator<JOIN*> j(joins);
JOIN** join;
while ((join= j++))
for (SELECT_LEX *sl= first_select(); sl; sl= sl->next_select())
{
(*join)->cleanup(thd);
delete *join;
JOIN *join;
if ((join= sl->join))
{
error|= sl->join->cleanup(thd);
delete join;
}
joins.empty();
DBUG_RETURN(0);
}
DBUG_RETURN(error);
}
......@@ -50,7 +50,7 @@ int mysql_update(THD *thd,
List<Item> &fields,
List<Item> &values,
COND *conds,
ORDER *order,
uint order_num, ORDER *order,
ha_rows limit,
enum enum_duplicates handle_duplicates)
{
......@@ -109,7 +109,7 @@ int mysql_update(THD *thd,
/* Check the fields we are going to modify */
table->grant.want_privilege=want_privilege;
if (setup_fields(thd,update_table_list,fields,1,0,0))
if (setup_fields(thd, 0, update_table_list, fields, 1, 0, 0))
DBUG_RETURN(-1); /* purecov: inspected */
if (table->timestamp_field)
{
......@@ -122,8 +122,9 @@ int mysql_update(THD *thd,
/* Check values */
table->grant.want_privilege=(SELECT_ACL & ~table->grant.privilege);
if (setup_fields(thd,update_table_list,values,0,0,0))
if (setup_fields(thd, 0, update_table_list, values, 0, 0, 0))
{
free_ulderlayed_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1); /* purecov: inspected */
}
......@@ -134,6 +135,7 @@ int mysql_update(THD *thd,
(select && select->check_quick(safe_update, limit)) || !limit)
{
delete select;
free_ulderlayed_joins(thd, &thd->lex.select_lex);
if (error)
{
DBUG_RETURN(-1); // Error in where
......@@ -148,6 +150,7 @@ int mysql_update(THD *thd,
if (safe_update && !using_limit)
{
delete select;
free_ulderlayed_joins(thd, &thd->lex.select_lex);
send_error(thd,ER_UPDATE_WITHOUT_KEY_IN_SAFE_MODE);
DBUG_RETURN(1);
}
......@@ -175,6 +178,7 @@ int mysql_update(THD *thd,
DISK_BUFFER_SIZE, MYF(MY_WME)))
{
delete select; /* purecov: inspected */
free_ulderlayed_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1);
}
if (old_used_keys & ((key_map) 1 << used_index))
......@@ -197,7 +201,10 @@ int mysql_update(THD *thd,
table->io_cache = (IO_CACHE *) my_malloc(sizeof(IO_CACHE),
MYF(MY_FAE | MY_ZEROFILL));
if (setup_order(thd, &tables, fields, all_fields, order) ||
if (setup_ref_array(thd, &thd->lex.select_lex.ref_pointer_array,
order_num)||
setup_order(thd, thd->lex.select_lex.ref_pointer_array,
&tables, fields, all_fields, order) ||
!(sortorder=make_unireg_sortorder(order, &length)) ||
(table->found_records = filesort(thd, table, sortorder, length,
(SQL_SELECT *) 0,
......@@ -205,6 +212,7 @@ int mysql_update(THD *thd,
== HA_POS_ERROR)
{
delete select;
free_ulderlayed_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1);
}
}
......@@ -258,6 +266,7 @@ int mysql_update(THD *thd,
if (error >= 0)
{
delete select;
free_ulderlayed_joins(thd, &thd->lex.select_lex);
DBUG_RETURN(-1);
}
}
......@@ -343,6 +352,7 @@ int mysql_update(THD *thd,
}
delete select;
free_ulderlayed_joins(thd, &thd->lex.select_lex);
if (error >= 0)
send_error(thd,thd->killed ? ER_SERVER_SHUTDOWN : 0); /* purecov: inspected */
else
......@@ -357,6 +367,7 @@ int mysql_update(THD *thd,
}
thd->count_cuted_fields=0; /* calc cuted fields */
free_io_cache(table);
DBUG_RETURN(0);
}
......@@ -388,7 +399,7 @@ int mysql_multi_update(THD *thd,
DBUG_RETURN(res);
thd->select_limit=HA_POS_ERROR;
if (setup_fields(thd, table_list, *fields, 1, 0, 0))
if (setup_fields(thd, 0, table_list, *fields, 1, 0, 0))
DBUG_RETURN(-1);
/*
......@@ -411,8 +422,9 @@ int mysql_multi_update(THD *thd,
DBUG_RETURN(-1);
List<Item> total_list;
res= mysql_select(thd,table_list,total_list,
conds, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
res= mysql_select(thd, &select_lex->ref_pointer_array,
table_list, select_lex->with_wild, total_list,
conds, 0, (ORDER *) NULL, (ORDER *)NULL, (Item *) NULL,
(ORDER *)NULL,
options | SELECT_NO_JOIN_CACHE,
result, unit, select_lex, 0);
......@@ -467,7 +479,7 @@ int multi_update::prepare(List<Item> &not_used_values, SELECT_LEX_UNIT *unit)
reference tables
*/
if (setup_fields(thd, all_tables, *values, 1,0,0))
if (setup_fields(thd, 0, all_tables, *values, 1, 0, 0))
DBUG_RETURN(1);
/*
......
......@@ -1760,8 +1760,10 @@ select_item_list:
| select_item
| '*'
{
if (add_item_to_list(YYTHD, new Item_field(NULL,NULL,"*")))
THD *thd= YYTHD;
if (add_item_to_list(thd, new Item_field(NULL, NULL, "*")))
YYABORT;
(thd->lex.current_select->select_lex()->with_wild)++;
};
......@@ -3631,10 +3633,19 @@ insert_ident:
| table_wild { $$=$1; };
table_wild:
ident '.' '*' { $$ = new Item_field(NullS,$1.str,"*"); }
ident '.' '*'
{
$$ = new Item_field(NullS,$1.str,"*");
Lex->current_select->select_lex()->with_wild++;
}
| ident '.' ident '.' '*'
{ $$ = new Item_field((YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str),$3.str,"*"); };
{
$$ = new Item_field((YYTHD->client_capabilities &
CLIENT_NO_SCHEMA ? NullS : $1.str),
$3.str,"*");
Lex->current_select->select_lex()->with_wild++;
}
;
order_ident:
expr { $$=$1; };
......
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