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

DBUG_ASSERT(fixed == 0) added to fix_fields()

parent b8c065c5
...@@ -103,21 +103,33 @@ void Item::print_item_w_name(String *str) ...@@ -103,21 +103,33 @@ void Item::print_item_w_name(String *str)
Item_ident::Item_ident(const char *db_name_par,const char *table_name_par, Item_ident::Item_ident(const char *db_name_par,const char *table_name_par,
const char *field_name_par) const char *field_name_par)
:db_name(db_name_par),table_name(table_name_par),field_name(field_name_par), :changed_during_fix_field(0), db_name(db_name_par),
table_name(table_name_par), field_name(field_name_par),
depended_from(0) depended_from(0)
{ {
name = (char*) field_name_par; name = (char*) field_name_par;
} }
// Constructor used by Item_field & Item_ref (see Item comment) // Constructor used by Item_field & Item_ref (see Item comment)
Item_ident::Item_ident(THD *thd, Item_ident *item): Item_ident::Item_ident(THD *thd, Item_ident *item)
Item(thd, item), :Item(thd, item),
db_name(item->db_name), changed_during_fix_field(0),
table_name(item->table_name), db_name(item->db_name),
field_name(item->field_name), table_name(item->table_name),
depended_from(item->depended_from) field_name(item->field_name),
depended_from(item->depended_from)
{} {}
void Item_ident::cleanup()
{
Item::cleanup();
if (changed_during_fix_field)
{
*changed_during_fix_field= this;
changed_during_fix_field= 0;
}
}
bool Item_ident::remove_dependence_processor(byte * arg) bool Item_ident::remove_dependence_processor(byte * arg)
{ {
DBUG_ENTER("Item_ident::remove_dependence_processor"); DBUG_ENTER("Item_ident::remove_dependence_processor");
...@@ -289,11 +301,14 @@ bool DTCollation::aggregate(DTCollation &dt) ...@@ -289,11 +301,14 @@ bool DTCollation::aggregate(DTCollation &dt)
return 0; return 0;
} }
Item_field::Item_field(Field *f) :Item_ident(NullS,f->table_name,f->field_name) Item_field::Item_field(Field *f)
:Item_ident(NullS, f->table_name, f->field_name)
#ifndef DBUG_OFF
,double_fix(0)
#endif
{ {
set_field(f); set_field(f);
collation.set(DERIVATION_IMPLICIT); collation.set(DERIVATION_IMPLICIT);
fixed= 1; // This item is not needed in fix_fields
} }
// Constructor need to process subselect with temporary tables (see Item) // Constructor need to process subselect with temporary tables (see Item)
...@@ -301,6 +316,9 @@ Item_field::Item_field(THD *thd, Item_field *item) ...@@ -301,6 +316,9 @@ Item_field::Item_field(THD *thd, Item_field *item)
:Item_ident(thd, item), :Item_ident(thd, item),
field(item->field), field(item->field),
result_field(item->result_field) result_field(item->result_field)
#ifndef DBUG_OFF
,double_fix(0)
#endif
{ {
collation.set(DERIVATION_IMPLICIT); collation.set(DERIVATION_IMPLICIT);
} }
...@@ -786,6 +804,9 @@ bool Item::fix_fields(THD *thd, ...@@ -786,6 +804,9 @@ bool Item::fix_fields(THD *thd,
struct st_table_list *list, struct st_table_list *list,
Item ** ref) Item ** ref)
{ {
// We do not check fields which are fixed during construction
DBUG_ASSERT(fixed == 0 || type() == INT_ITEM || type() == CACHE_ITEM);
fixed= 1; fixed= 1;
return 0; return 0;
} }
...@@ -847,6 +868,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current, ...@@ -847,6 +868,7 @@ static void mark_as_dependent(THD *thd, SELECT_LEX *last, SELECT_LEX *current,
bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0 || double_fix == 0);
if (!field) // If field is not checked if (!field) // If field is not checked
{ {
TABLE_LIST *where= 0; TABLE_LIST *where= 0;
...@@ -952,6 +974,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -952,6 +974,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
ref, ref,
(char *)table_name, (char *)table_name,
(char *)field_name); (char *)field_name);
register_item_tree_changing(ref);
if (!rf) if (!rf)
return 1; return 1;
/* /*
...@@ -1005,6 +1028,11 @@ void Item_field::cleanup() ...@@ -1005,6 +1028,11 @@ void Item_field::cleanup()
{ {
DBUG_ENTER("Item_field::cleanup"); DBUG_ENTER("Item_field::cleanup");
Item_ident::cleanup(); Item_ident::cleanup();
/*
Even if this object was created by direct link to field in setup_wild()
it will be linked correctly next tyme by name of field and table alias.
I.e. we can drop 'field'.
*/
field= result_field= 0; field= result_field= 0;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
...@@ -1480,6 +1508,7 @@ bool Item_field::send(Protocol *protocol, String *buffer) ...@@ -1480,6 +1508,7 @@ bool Item_field::send(Protocol *protocol, String *buffer)
bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{ {
DBUG_ASSERT(fixed == 0);
uint counter; uint counter;
if (!ref) if (!ref)
{ {
...@@ -1585,6 +1614,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference) ...@@ -1585,6 +1614,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
Item_field* fld; Item_field* fld;
if (!((*reference)= fld= new Item_field(tmp))) if (!((*reference)= fld= new Item_field(tmp)))
return 1; return 1;
register_item_tree_changing(reference);
mark_as_dependent(thd, last, thd->lex->current_select, fld); mark_as_dependent(thd, last, thd->lex->current_select, fld);
return 0; return 0;
} }
...@@ -1696,6 +1726,7 @@ bool Item_default_value::fix_fields(THD *thd, ...@@ -1696,6 +1726,7 @@ bool Item_default_value::fix_fields(THD *thd,
struct st_table_list *table_list, struct st_table_list *table_list,
Item **items) Item **items)
{ {
DBUG_ASSERT(fixed == 0);
if (!arg) if (!arg)
return 0; return 0;
if (arg->fix_fields(thd, table_list, &arg)) if (arg->fix_fields(thd, table_list, &arg))
...@@ -1744,6 +1775,7 @@ bool Item_insert_value::fix_fields(THD *thd, ...@@ -1744,6 +1775,7 @@ bool Item_insert_value::fix_fields(THD *thd,
struct st_table_list *table_list, struct st_table_list *table_list,
Item **items) Item **items)
{ {
DBUG_ASSERT(fixed == 0);
if (arg->fix_fields(thd, table_list, &arg)) if (arg->fix_fields(thd, table_list, &arg))
return 1; return 1;
......
...@@ -233,7 +233,7 @@ class Item { ...@@ -233,7 +233,7 @@ class Item {
Field *tmp_table_field_from_field_type(TABLE *table); Field *tmp_table_field_from_field_type(TABLE *table);
/* Used in sql_select.cc:eliminate_not_funcs() */ /* Used in sql_select.cc:eliminate_not_funcs() */
virtual Item *neg_transformer() { return NULL; } virtual Item *neg_transformer(THD *thd) { return NULL; }
void delete_self() void delete_self()
{ {
cleanup(); cleanup();
...@@ -245,6 +245,7 @@ class Item { ...@@ -245,6 +245,7 @@ class Item {
class st_select_lex; class st_select_lex;
class Item_ident :public Item class Item_ident :public Item
{ {
Item **changed_during_fix_field;
public: public:
const char *db_name; const char *db_name;
const char *table_name; const char *table_name;
...@@ -254,7 +255,9 @@ class Item_ident :public Item ...@@ -254,7 +255,9 @@ class Item_ident :public Item
const char *field_name_par); const char *field_name_par);
Item_ident(THD *thd, Item_ident *item); Item_ident(THD *thd, Item_ident *item);
const char *full_name() const; const char *full_name() const;
void cleanup();
void register_item_tree_changing(Item **ref)
{ changed_during_fix_field= ref; }
bool remove_dependence_processor(byte * arg); bool remove_dependence_processor(byte * arg);
}; };
...@@ -264,11 +267,17 @@ class Item_field :public Item_ident ...@@ -264,11 +267,17 @@ class Item_field :public Item_ident
void set_field(Field *field); void set_field(Field *field);
public: public:
Field *field,*result_field; Field *field,*result_field;
// Item_field() {} #ifndef DBUG_OFF
bool double_fix;
#endif
Item_field(const char *db_par,const char *table_name_par, Item_field(const char *db_par,const char *table_name_par,
const char *field_name_par) const char *field_name_par)
:Item_ident(db_par,table_name_par,field_name_par),field(0),result_field(0) :Item_ident(db_par,table_name_par,field_name_par),
field(0), result_field(0)
#ifndef DBUG_OFF
,double_fix(0)
#endif
{ collation.set(DERIVATION_IMPLICIT); } { collation.set(DERIVATION_IMPLICIT); }
// Constructor need to process subselect with temporary tables (see Item) // Constructor need to process subselect with temporary tables (see Item)
Item_field(THD *thd, Item_field *item); Item_field(THD *thd, Item_field *item);
...@@ -324,6 +333,7 @@ class Item_null :public Item ...@@ -324,6 +333,7 @@ class Item_null :public Item
enum_field_types field_type() const { return MYSQL_TYPE_NULL; } enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
bool fix_fields(THD *thd, struct st_table_list *list, Item **item) bool fix_fields(THD *thd, struct st_table_list *list, Item **item)
{ {
DBUG_ASSERT(fixed == 0);
bool res= Item::fix_fields(thd, list, item); bool res= Item::fix_fields(thd, list, item);
max_length=0; max_length=0;
return res; return res;
...@@ -413,7 +423,8 @@ class Item_int :public Item ...@@ -413,7 +423,8 @@ class Item_int :public Item
int save_in_field(Field *field, bool no_conversions); int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; } bool basic_const_item() const { return 1; }
Item *new_item() { return new Item_int(name,value,max_length); } Item *new_item() { return new Item_int(name,value,max_length); }
void cleanup() { fixed= 1; } // to prevent drop fixed flag // to prevent drop fixed flag (no need parent cleanup call)
void cleanup() { fixed= 1; }
void print(String *str); void print(String *str);
}; };
...@@ -422,14 +433,17 @@ class Item_uint :public Item_int ...@@ -422,14 +433,17 @@ class Item_uint :public Item_int
{ {
public: public:
Item_uint(const char *str_arg, uint length) : Item_uint(const char *str_arg, uint length) :
Item_int(str_arg, (longlong) strtoull(str_arg,(char**) 0,10), length) {} Item_int(str_arg, (longlong) strtoull(str_arg,(char**) 0,10), length)
Item_uint(uint32 i) :Item_int((longlong) i, 10) {} { fixed= 0; }
Item_uint(uint32 i) :Item_int((longlong) i, 10)
{ fixed= 0; }
double val() { return ulonglong2double((ulonglong)value); } double val() { return ulonglong2double((ulonglong)value); }
String *val_str(String*); String *val_str(String*);
Item *new_item() { return new Item_uint(name,max_length); } Item *new_item() { return new Item_uint(name,max_length); }
int save_in_field(Field *field, bool no_conversions); int save_in_field(Field *field, bool no_conversions);
bool fix_fields(THD *thd, struct st_table_list *list, Item **item) bool fix_fields(THD *thd, struct st_table_list *list, Item **item)
{ {
DBUG_ASSERT(fixed == 0);
bool res= Item::fix_fields(thd, list, item); bool res= Item::fix_fields(thd, list, item);
unsigned_flag= 1; unsigned_flag= 1;
return res; return res;
...@@ -903,7 +917,8 @@ class Item_cache: public Item ...@@ -903,7 +917,8 @@ class Item_cache: public Item
static Item_cache* get_cache(Item_result type); static Item_cache* get_cache(Item_result type);
table_map used_tables() const { return used_table_map; } table_map used_tables() const { return used_table_map; }
virtual void keep_array() {} virtual void keep_array() {}
void cleanup() { fixed= 1; } // to prevent drop fixed flag // to prevent drop fixed flag (no need parent cleanup call)
void cleanup() { fixed= 1; }
void print(String *str); void print(String *str);
}; };
......
...@@ -502,7 +502,6 @@ bool Item_in_optimizer::fix_left(THD *thd, ...@@ -502,7 +502,6 @@ bool Item_in_optimizer::fix_left(THD *thd,
not_null_tables_cache= args[0]->not_null_tables(); not_null_tables_cache= args[0]->not_null_tables();
with_sum_func= args[0]->with_sum_func; with_sum_func= args[0]->with_sum_func;
const_item_cache= args[0]->const_item(); const_item_cache= args[0]->const_item();
fixed= 1;
return 0; return 0;
} }
...@@ -510,7 +509,8 @@ bool Item_in_optimizer::fix_left(THD *thd, ...@@ -510,7 +509,8 @@ bool Item_in_optimizer::fix_left(THD *thd,
bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
Item ** ref) Item ** ref)
{ {
if (fix_left(thd, tables, ref)) DBUG_ASSERT(fixed == 0);
if (!args[0]->fixed && fix_left(thd, tables, ref))
return 1; return 1;
if (args[0]->maybe_null) if (args[0]->maybe_null)
maybe_null=1; maybe_null=1;
...@@ -529,6 +529,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables, ...@@ -529,6 +529,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
used_tables_cache|= args[1]->used_tables(); used_tables_cache|= args[1]->used_tables();
not_null_tables_cache|= args[1]->not_null_tables(); not_null_tables_cache|= args[1]->not_null_tables();
const_item_cache&= args[1]->const_item(); const_item_cache&= args[1]->const_item();
fixed= 1;
return 0; return 0;
} }
...@@ -1755,6 +1756,7 @@ void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item) ...@@ -1755,6 +1756,7 @@ void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item)
bool bool
Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
List_iterator<Item> li(list); List_iterator<Item> li(list);
Item *item; Item *item;
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
...@@ -1878,14 +1880,27 @@ void Item_cond::print(String *str) ...@@ -1878,14 +1880,27 @@ void Item_cond::print(String *str)
} }
void Item_cond::neg_arguments() void Item_cond::neg_arguments(THD *thd)
{ {
List_iterator<Item> li(list); List_iterator<Item> li(list);
Item *item; Item *item;
while ((item= li++)) /* Apply not transformation to the arguments */ while ((item= li++)) /* Apply not transformation to the arguments */
{ {
Item *new_item= item->neg_transformer(); Item *new_item= item->neg_transformer(thd);
VOID(li.replace(new_item ? new_item : new Item_func_not(item))); if (!new_item)
{
new_item= new Item_func_not(item);
/*
We can use 0 as tables list because Item_func_not do not use it
on fix_fields and its arguments are already fixed.
We do not check results of fix_fields, because there are not way
to return error in this functions interface, thd->net.report_error
will be checked on upper level call.
*/
new_item->fix_fields(thd, 0, &new_item);
}
VOID(li.replace(new_item));
} }
} }
...@@ -2097,6 +2112,7 @@ Item_func::optimize_type Item_func_like::select_optimize() const ...@@ -2097,6 +2112,7 @@ Item_func::optimize_type Item_func_like::select_optimize() const
bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
{ {
DBUG_ASSERT(fixed == 0);
if (Item_bool_func2::fix_fields(thd, tlist, ref)) if (Item_bool_func2::fix_fields(thd, tlist, ref))
return 1; return 1;
...@@ -2150,6 +2166,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref) ...@@ -2150,6 +2166,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
bool bool
Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) Item_func_regex::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
if (args[0]->fix_fields(thd, tables, args) || args[0]->check_cols(1) || if (args[0]->fix_fields(thd, tables, args) || args[0]->check_cols(1) ||
args[1]->fix_fields(thd,tables, args + 1) || args[1]->check_cols(1)) args[1]->fix_fields(thd,tables, args + 1) || args[1]->check_cols(1))
return 1; /* purecov: inspected */ return 1; /* purecov: inspected */
...@@ -2518,6 +2535,7 @@ longlong Item_cond_xor::val_int() ...@@ -2518,6 +2535,7 @@ longlong Item_cond_xor::val_int()
SYNPOSIS SYNPOSIS
neg_transformer() neg_transformer()
thd thread handler
DESCRIPTION DESCRIPTION
Transform the item using next rules: Transform the item using next rules:
...@@ -2541,62 +2559,116 @@ longlong Item_cond_xor::val_int() ...@@ -2541,62 +2559,116 @@ longlong Item_cond_xor::val_int()
NULL if we cannot apply NOT transformation (see Item::neg_transformer()). NULL if we cannot apply NOT transformation (see Item::neg_transformer()).
*/ */
Item *Item_func_not::neg_transformer() /* NOT(x) -> x */ Item *Item_func_not::neg_transformer(THD *thd) /* NOT(x) -> x */
{ {
/* We should apply negation elimination to the argument of the NOT function */ // We should apply negation elimination to the argument of the NOT function
return eliminate_not_funcs(args[0]); return eliminate_not_funcs(thd, args[0]);
} }
Item *Item_func_eq::neg_transformer() /* a = b -> a != b */
Item *Item_bool_rowready_func2::neg_transformer(THD *thd)
{ {
return new Item_func_ne(args[0], args[1]); Item *item= negated_item();
if (item)
{
/*
We can use 0 as tables list because Item_func* family do not use it
on fix_fields and its arguments are already fixed.
We do not check results of fix_fields, because there are not way
to return error in this functions interface, thd->net.report_error
will be checked on upper level call.
*/
item->fix_fields(thd, 0, &item);
}
return item;
} }
Item *Item_func_ne::neg_transformer() /* a != b -> a = b */
/* a IS NULL -> a IS NOT NULL */
Item *Item_func_isnull::neg_transformer(THD *thd)
{ {
return new Item_func_eq(args[0], args[1]); Item *item= new Item_func_isnotnull(args[0]);
// see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
if (item)
item->fix_fields(thd, 0, &item);
return item;
} }
Item *Item_func_lt::neg_transformer() /* a < b -> a >= b */
/* a IS NOT NULL -> a IS NULL */
Item *Item_func_isnotnull::neg_transformer(THD *thd)
{ {
return new Item_func_ge(args[0], args[1]); Item *item= new Item_func_isnull(args[0]);
// see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
if (item)
item->fix_fields(thd, 0, &item);
return item;
} }
Item *Item_func_ge::neg_transformer() /* a >= b -> a < b */
Item *Item_cond_and::neg_transformer(THD *thd) /* NOT(a AND b AND ...) -> */
/* NOT a OR NOT b OR ... */
{ {
return new Item_func_lt(args[0], args[1]); neg_arguments(thd);
Item *item= new Item_cond_or(list);
// see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
if (item)
item->fix_fields(thd, 0, &item);
return item;
} }
Item *Item_func_gt::neg_transformer() /* a > b -> a <= b */
Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */
/* NOT a AND NOT b AND ... */
{ {
return new Item_func_le(args[0], args[1]); neg_arguments(thd);
Item *item= new Item_cond_and(list);
// see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
if (item)
item->fix_fields(thd, 0, &item);
return item;
} }
Item *Item_func_le::neg_transformer() /* a <= b -> a > b */
Item *Item_func_eq::negated_item() /* a = b -> a != b */
{ {
return new Item_func_gt(args[0], args[1]); return new Item_func_ne(args[0], args[1]);
} }
Item *Item_func_isnull::neg_transformer() /* a IS NULL -> a IS NOT NULL */
Item *Item_func_ne::negated_item() /* a != b -> a = b */
{ {
return new Item_func_isnotnull(args[0]); return new Item_func_eq(args[0], args[1]);
} }
Item *Item_func_isnotnull::neg_transformer() /* a IS NOT NULL -> a IS NULL */
Item *Item_func_lt::negated_item() /* a < b -> a >= b */
{ {
return new Item_func_isnull(args[0]); return new Item_func_ge(args[0], args[1]);
} }
Item *Item_cond_and::neg_transformer() /* NOT(a AND b AND ...) -> */
/* NOT a OR NOT b OR ... */ Item *Item_func_ge::negated_item() /* a >= b -> a < b */
{ {
neg_arguments(); return new Item_func_lt(args[0], args[1]);
return new Item_cond_or(list);
} }
Item *Item_cond_or::neg_transformer() /* NOT(a OR b OR ...) -> */
/* NOT a AND NOT b AND ... */ Item *Item_func_gt::negated_item() /* a > b -> a <= b */
{ {
neg_arguments(); return new Item_func_le(args[0], args[1]);
return new Item_cond_and(list); }
Item *Item_func_le::negated_item() /* a <= b -> a > b */
{
return new Item_func_gt(args[0], args[1]);
}
// just fake method, should never be called
Item *Item_bool_rowready_func2::negated_item()
{
DBUG_ASSERT(0);
return 0;
} }
...@@ -218,6 +218,8 @@ class Item_bool_rowready_func2 :public Item_bool_func2 ...@@ -218,6 +218,8 @@ class Item_bool_rowready_func2 :public Item_bool_func2
tmp_arg[1]= orig_b; tmp_arg[1]= orig_b;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
Item *neg_transformer(THD *thd);
virtual Item *negated_item();
}; };
class Item_func_not :public Item_bool_func class Item_func_not :public Item_bool_func
...@@ -227,7 +229,7 @@ class Item_func_not :public Item_bool_func ...@@ -227,7 +229,7 @@ class Item_func_not :public Item_bool_func
longlong val_int(); longlong val_int();
enum Functype functype() const { return NOT_FUNC; } enum Functype functype() const { return NOT_FUNC; }
const char *func_name() const { return "not"; } const char *func_name() const { return "not"; }
Item *neg_transformer(); Item *neg_transformer(THD *thd);
}; };
class Item_func_not_all :public Item_func_not class Item_func_not_all :public Item_func_not
...@@ -254,7 +256,7 @@ class Item_func_eq :public Item_bool_rowready_func2 ...@@ -254,7 +256,7 @@ class Item_func_eq :public Item_bool_rowready_func2
enum Functype rev_functype() const { return EQ_FUNC; } enum Functype rev_functype() const { return EQ_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; } cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return "="; } const char *func_name() const { return "="; }
Item *neg_transformer(); Item *negated_item();
}; };
class Item_func_equal :public Item_bool_rowready_func2 class Item_func_equal :public Item_bool_rowready_func2
...@@ -267,6 +269,7 @@ class Item_func_equal :public Item_bool_rowready_func2 ...@@ -267,6 +269,7 @@ class Item_func_equal :public Item_bool_rowready_func2
enum Functype rev_functype() const { return EQUAL_FUNC; } enum Functype rev_functype() const { return EQUAL_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; } cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return "<=>"; } const char *func_name() const { return "<=>"; }
Item* neg_transformer(THD *thd) { return 0; }
}; };
...@@ -279,7 +282,7 @@ class Item_func_ge :public Item_bool_rowready_func2 ...@@ -279,7 +282,7 @@ class Item_func_ge :public Item_bool_rowready_func2
enum Functype rev_functype() const { return LE_FUNC; } enum Functype rev_functype() const { return LE_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; } cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return ">="; } const char *func_name() const { return ">="; }
Item *neg_transformer(); Item *negated_item();
}; };
...@@ -292,7 +295,7 @@ class Item_func_gt :public Item_bool_rowready_func2 ...@@ -292,7 +295,7 @@ class Item_func_gt :public Item_bool_rowready_func2
enum Functype rev_functype() const { return LT_FUNC; } enum Functype rev_functype() const { return LT_FUNC; }
cond_result eq_cmp_result() const { return COND_FALSE; } cond_result eq_cmp_result() const { return COND_FALSE; }
const char *func_name() const { return ">"; } const char *func_name() const { return ">"; }
Item *neg_transformer(); Item *negated_item();
}; };
...@@ -305,7 +308,7 @@ class Item_func_le :public Item_bool_rowready_func2 ...@@ -305,7 +308,7 @@ class Item_func_le :public Item_bool_rowready_func2
enum Functype rev_functype() const { return GE_FUNC; } enum Functype rev_functype() const { return GE_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; } cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return "<="; } const char *func_name() const { return "<="; }
Item *neg_transformer(); Item *negated_item();
}; };
...@@ -318,7 +321,7 @@ class Item_func_lt :public Item_bool_rowready_func2 ...@@ -318,7 +321,7 @@ class Item_func_lt :public Item_bool_rowready_func2
enum Functype rev_functype() const { return GT_FUNC; } enum Functype rev_functype() const { return GT_FUNC; }
cond_result eq_cmp_result() const { return COND_FALSE; } cond_result eq_cmp_result() const { return COND_FALSE; }
const char *func_name() const { return "<"; } const char *func_name() const { return "<"; }
Item *neg_transformer(); Item *negated_item();
}; };
...@@ -331,7 +334,7 @@ class Item_func_ne :public Item_bool_rowready_func2 ...@@ -331,7 +334,7 @@ class Item_func_ne :public Item_bool_rowready_func2
cond_result eq_cmp_result() const { return COND_FALSE; } cond_result eq_cmp_result() const { return COND_FALSE; }
optimize_type select_optimize() const { return OPTIMIZE_KEY; } optimize_type select_optimize() const { return OPTIMIZE_KEY; }
const char *func_name() const { return "<>"; } const char *func_name() const { return "<>"; }
Item *neg_transformer(); Item *negated_item();
}; };
...@@ -409,6 +412,7 @@ class Item_func_if :public Item_func ...@@ -409,6 +412,7 @@ class Item_func_if :public Item_func
enum Item_result result_type () const { return cached_result_type; } enum Item_result result_type () const { return cached_result_type; }
bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref) bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
args[0]->top_level_item(); args[0]->top_level_item();
return Item_func::fix_fields(thd, tlist, ref); return Item_func::fix_fields(thd, tlist, ref);
} }
...@@ -726,6 +730,7 @@ class Item_func_in :public Item_int_func ...@@ -726,6 +730,7 @@ class Item_func_in :public Item_int_func
void cleanup() void cleanup()
{ {
DBUG_ENTER("Item_func_in::cleanup"); DBUG_ENTER("Item_func_in::cleanup");
Item_int_func::cleanup();
delete array; delete array;
delete in_item; delete in_item;
array= 0; array= 0;
...@@ -778,7 +783,7 @@ class Item_func_isnull :public Item_bool_func ...@@ -778,7 +783,7 @@ class Item_func_isnull :public Item_bool_func
} }
table_map not_null_tables() const { return 0; } table_map not_null_tables() const { return 0; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; } optimize_type select_optimize() const { return OPTIMIZE_NULL; }
Item *neg_transformer(); Item *neg_transformer(THD *thd);
CHARSET_INFO *compare_collation() { return args[0]->collation.collation; } CHARSET_INFO *compare_collation() { return args[0]->collation.collation; }
}; };
...@@ -812,7 +817,7 @@ class Item_func_isnotnull :public Item_bool_func ...@@ -812,7 +817,7 @@ class Item_func_isnotnull :public Item_bool_func
const char *func_name() const { return "isnotnull"; } const char *func_name() const { return "isnotnull"; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; } optimize_type select_optimize() const { return OPTIMIZE_NULL; }
table_map not_null_tables() const { return 0; } table_map not_null_tables() const { return 0; }
Item *neg_transformer(); Item *neg_transformer(THD *thd);
void print(String *str); void print(String *str);
CHARSET_INFO *compare_collation() { return args[0]->collation.collation; } CHARSET_INFO *compare_collation() { return args[0]->collation.collation; }
}; };
...@@ -920,7 +925,7 @@ class Item_cond :public Item_bool_func ...@@ -920,7 +925,7 @@ class Item_cond :public Item_bool_func
void top_level_item() { abort_on_null=1; } void top_level_item() { abort_on_null=1; }
void copy_andor_arguments(THD *thd, Item_cond *item); void copy_andor_arguments(THD *thd, Item_cond *item);
bool walk(Item_processor processor, byte *arg); bool walk(Item_processor processor, byte *arg);
void neg_arguments(); void neg_arguments(THD *thd);
}; };
...@@ -941,7 +946,7 @@ class Item_cond_and :public Item_cond ...@@ -941,7 +946,7 @@ class Item_cond_and :public Item_cond
item->copy_andor_arguments(thd, this); item->copy_andor_arguments(thd, this);
return item; return item;
} }
Item *neg_transformer(); Item *neg_transformer(THD *thd);
}; };
class Item_cond_or :public Item_cond class Item_cond_or :public Item_cond
...@@ -962,7 +967,7 @@ class Item_cond_or :public Item_cond ...@@ -962,7 +967,7 @@ class Item_cond_or :public Item_cond
item->copy_andor_arguments(thd, this); item->copy_andor_arguments(thd, this);
return item; return item;
} }
Item *neg_transformer(); Item *neg_transformer(THD *thd);
}; };
......
...@@ -199,6 +199,7 @@ Item_func::Item_func(THD *thd, Item_func *item) ...@@ -199,6 +199,7 @@ Item_func::Item_func(THD *thd, Item_func *item)
bool bool
Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
Item **arg,**arg_end; Item **arg,**arg_end;
#ifndef EMBEDDED_LIBRARY // Avoid compiler warning #ifndef EMBEDDED_LIBRARY // Avoid compiler warning
char buff[STACK_BUFF_ALLOC]; // Max argument in function char buff[STACK_BUFF_ALLOC]; // Max argument in function
...@@ -215,7 +216,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -215,7 +216,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
Item *item; Item *item;
/* We can't yet set item to *arg as fix_fields may change *arg */ /* We can't yet set item to *arg as fix_fields may change *arg */
if ((*arg)->fix_fields(thd, tables, arg) || if ((!(*arg)->fixed && (*arg)->fix_fields(thd, tables, arg)) ||
(*arg)->check_cols(allowed_arg_cols)) (*arg)->check_cols(allowed_arg_cols))
return 1; /* purecov: inspected */ return 1; /* purecov: inspected */
item= *arg; item= *arg;
...@@ -2172,6 +2173,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name, ...@@ -2172,6 +2173,7 @@ static user_var_entry *get_variable(HASH *hash, LEX_STRING &name,
bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables, bool Item_func_set_user_var::fix_fields(THD *thd, TABLE_LIST *tables,
Item **ref) Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
/* fix_fields will call Item_func_set_user_var::fix_length_and_dec */ /* fix_fields will call Item_func_set_user_var::fix_length_and_dec */
if (Item_func::fix_fields(thd, tables, ref) || if (Item_func::fix_fields(thd, tables, ref) ||
!(entry= get_variable(&thd->user_vars, name, 1))) !(entry= get_variable(&thd->user_vars, name, 1)))
...@@ -2741,6 +2743,7 @@ void Item_func_match::init_search(bool no_order) ...@@ -2741,6 +2743,7 @@ void Item_func_match::init_search(bool no_order)
bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
Item *item; Item *item;
LINT_INIT(item); // Safe as arg_count is > 1 LINT_INIT(item); // Safe as arg_count is > 1
......
...@@ -765,6 +765,7 @@ class Item_udf_func :public Item_func ...@@ -765,6 +765,7 @@ class Item_udf_func :public Item_func
const char *func_name() const { return udf.name(); } const char *func_name() const { return udf.name(); }
bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref) bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
bool res= udf.fix_fields(thd, tables, this, arg_count, args); bool res= udf.fix_fields(thd, tables, this, arg_count, args);
used_tables_cache= udf.used_tables_cache; used_tables_cache= udf.used_tables_cache;
const_item_cache= udf.const_item_cache; const_item_cache= udf.const_item_cache;
...@@ -1000,6 +1001,7 @@ class Item_func_match :public Item_real_func ...@@ -1000,6 +1001,7 @@ class Item_func_match :public Item_real_func
void cleanup() void cleanup()
{ {
DBUG_ENTER("Item_func_match"); DBUG_ENTER("Item_func_match");
Item_real_func::cleanup();
if (!master && ft_handler) if (!master && ft_handler)
{ {
ft_handler->please->close_search(ft_handler); ft_handler->please->close_search(ft_handler);
......
...@@ -55,6 +55,7 @@ void Item_row::illegal_method_call(const char *method) ...@@ -55,6 +55,7 @@ void Item_row::illegal_method_call(const char *method)
bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
null_value= 0; null_value= 0;
maybe_null= 0; maybe_null= 0;
Item **arg, **arg_end; Item **arg, **arg_end;
...@@ -78,6 +79,7 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref) ...@@ -78,6 +79,7 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
maybe_null|= item->maybe_null; maybe_null|= item->maybe_null;
with_sum_func= with_sum_func || item->with_sum_func; with_sum_func= with_sum_func || item->with_sum_func;
} }
fixed= 1;
return 0; return 0;
} }
......
...@@ -100,6 +100,7 @@ class Item_func_concat_ws :public Item_str_func ...@@ -100,6 +100,7 @@ class Item_func_concat_ws :public Item_str_func
void update_used_tables(); void update_used_tables();
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
return (separator->fix_fields(thd, tlist, &separator) || return (separator->fix_fields(thd, tlist, &separator) ||
separator->check_cols(1) || separator->check_cols(1) ||
Item_func::fix_fields(thd, tlist, ref)); Item_func::fix_fields(thd, tlist, ref));
...@@ -411,6 +412,7 @@ class Item_func_make_set :public Item_str_func ...@@ -411,6 +412,7 @@ class Item_func_make_set :public Item_str_func
String *val_str(String *str); String *val_str(String *str);
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
return (item->fix_fields(thd, tlist, &item) || return (item->fix_fields(thd, tlist, &item) ||
item->check_cols(1) || item->check_cols(1) ||
Item_func::fix_fields(thd, tlist, ref)); Item_func::fix_fields(thd, tlist, ref));
......
...@@ -102,6 +102,7 @@ Item_subselect::select_transformer(JOIN *join) ...@@ -102,6 +102,7 @@ Item_subselect::select_transformer(JOIN *join)
bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param)); engine->set_thd((thd= thd_param));
stmt= thd->current_statement; stmt= thd->current_statement;
...@@ -125,8 +126,10 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref) ...@@ -125,8 +126,10 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
engine->exclude(); engine->exclude();
substitution= 0; substitution= 0;
fixed= 1; fixed= 1;
thd->where= "checking transformed subquery"; thd->where= "checking transformed subquery";
int ret= (*ref)->fix_fields(thd, tables, ref); int ret= 0;
if (!(*ref)->fixed)
ret= (*ref)->fix_fields(thd, tables, ref);
// We can't substitute aggregate functions (like (SELECT (max(i))) // We can't substitute aggregate functions (like (SELECT (max(i)))
if ((*ref)->with_sum_func) if ((*ref)->with_sum_func)
{ {
...@@ -651,9 +654,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, ...@@ -651,9 +654,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->item_list.empty(); select_lex->item_list.empty();
select_lex->item_list.push_back(item); select_lex->item_list.push_back(item);
if (item->fix_fields(thd, join->tables_list, // fix_fields call for 'item' will be made during new subquery fix_fields
select_lex->item_list.head_ref()))
goto err;
subs= new Item_singlerow_subselect(select_lex); subs= new Item_singlerow_subselect(select_lex);
} }
......
...@@ -162,6 +162,7 @@ Item_sum_int::val_str(String *str) ...@@ -162,6 +162,7 @@ Item_sum_int::val_str(String *str)
bool bool
Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
if (!thd->allow_sum_func) if (!thd->allow_sum_func)
{ {
my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0)); my_error(ER_INVALID_GROUP_FUNC_USE,MYF(0));
...@@ -191,6 +192,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) ...@@ -191,6 +192,7 @@ Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
bool bool
Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
Item *item= args[0]; Item *item= args[0];
if (!thd->allow_sum_func) if (!thd->allow_sum_func)
{ {
...@@ -1116,6 +1118,7 @@ void Item_sum_count_distinct::cleanup() ...@@ -1116,6 +1118,7 @@ void Item_sum_count_distinct::cleanup()
bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables, bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables,
Item **ref) Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
if (Item_sum_num::fix_fields(thd, tables, ref)) if (Item_sum_num::fix_fields(thd, tables, ref))
return 1; return 1;
return 0; return 0;
...@@ -1679,6 +1682,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct, ...@@ -1679,6 +1682,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
void Item_func_group_concat::cleanup() void Item_func_group_concat::cleanup()
{ {
DBUG_ENTER("Item_func_group_concat::cleanup"); DBUG_ENTER("Item_func_group_concat::cleanup");
Item_sum::cleanup();
/* /*
Free table and tree if they belong to this item (if item have not pointer Free table and tree if they belong to this item (if item have not pointer
to original item from which was made copy => it own its objects ) to original item from which was made copy => it own its objects )
...@@ -1794,6 +1798,7 @@ void Item_func_group_concat::reset_field() ...@@ -1794,6 +1798,7 @@ void Item_func_group_concat::reset_field()
bool bool
Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
uint i; /* for loop variable */ uint i; /* for loop variable */
if (!thd->allow_sum_func) if (!thd->allow_sum_func)
......
...@@ -533,6 +533,7 @@ class Item_udf_sum : public Item_sum ...@@ -533,6 +533,7 @@ class Item_udf_sum : public Item_sum
const char *func_name() const { return udf.name(); } const char *func_name() const { return udf.name(); }
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref) bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
fixed= 1; fixed= 1;
return udf.fix_fields(thd,tables,this,this->arg_count,this->args); return udf.fix_fields(thd,tables,this,this->arg_count,this->args);
} }
......
...@@ -48,6 +48,7 @@ class Item_sum_unique_users :public Item_sum_num ...@@ -48,6 +48,7 @@ class Item_sum_unique_users :public Item_sum_num
void update_field() {} void update_field() {}
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref) bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{ {
DBUG_ASSERT(fixed == 0);
fixed= 1; fixed= 1;
return 0; return 0;
} }
......
...@@ -2140,7 +2140,7 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables, ...@@ -2140,7 +2140,7 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
Item **ref= ref_pointer_array; Item **ref= ref_pointer_array;
while ((item= it++)) while ((item= it++))
{ {
if (item->fix_fields(thd, tables, it.ref()) || if (!item->fixed && item->fix_fields(thd, tables, it.ref()) ||
(item= *(it.ref()))->check_cols(1)) (item= *(it.ref()))->check_cols(1))
DBUG_RETURN(-1); /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */
if (ref) if (ref)
...@@ -2322,7 +2322,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -2322,7 +2322,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
if (*conds) if (*conds)
{ {
thd->where="where clause"; thd->where="where clause";
if ((*conds)->fix_fields(thd, tables, conds) || (*conds)->check_cols(1)) if (!(*conds)->fixed && (*conds)->fix_fields(thd, tables, conds) ||
(*conds)->check_cols(1))
DBUG_RETURN(1); DBUG_RETURN(1);
not_null_tables= (*conds)->not_null_tables(); not_null_tables= (*conds)->not_null_tables();
} }
...@@ -2334,7 +2335,9 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds) ...@@ -2334,7 +2335,9 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{ {
/* Make a join an a expression */ /* Make a join an a expression */
thd->where="on clause"; thd->where="on clause";
if (table->on_expr->fix_fields(thd, tables, &table->on_expr) ||
if (!table->on_expr->fixed &&
table->on_expr->fix_fields(thd, tables, &table->on_expr) ||
table->on_expr->check_cols(1)) table->on_expr->check_cols(1))
DBUG_RETURN(1); DBUG_RETURN(1);
thd->lex->current_select->cond_count++; thd->lex->current_select->cond_count++;
......
...@@ -151,7 +151,11 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, ...@@ -151,7 +151,11 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
if (is_union) if (is_union)
res= mysql_union(thd, lex, derived_result, unit); {
// execute union without clean up
if (!(res= unit->prepare(thd, derived_result, SELECT_NO_UNLOCK)))
res= unit->exec();
}
else else
{ {
unit->offset_limit_cnt= first_select->offset_limit; unit->offset_limit_cnt= first_select->offset_limit;
......
...@@ -70,8 +70,10 @@ static int return_zero_rows(JOIN *join, select_result *res,TABLE_LIST *tables, ...@@ -70,8 +70,10 @@ static int return_zero_rows(JOIN *join, select_result *res,TABLE_LIST *tables,
uint select_options, const char *info, uint select_options, const char *info,
Item *having, Procedure *proc, Item *having, Procedure *proc,
SELECT_LEX_UNIT *unit); SELECT_LEX_UNIT *unit);
static COND *optimize_cond(COND *conds,Item::cond_result *cond_value); static COND *optimize_cond(THD *thd, COND *conds,
static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value); Item::cond_result *cond_value);
static COND *remove_eq_conds(THD *thd, COND *cond,
Item::cond_result *cond_value);
static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item); static bool const_expression_in_where(COND *conds,Item *item, Item **comp_item);
static bool open_tmp_table(TABLE *table); static bool open_tmp_table(TABLE *table);
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param, static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
...@@ -286,6 +288,10 @@ JOIN::prepare(Item ***rref_pointer_array, ...@@ -286,6 +288,10 @@ JOIN::prepare(Item ***rref_pointer_array,
{ {
DBUG_ENTER("JOIN::prepare"); DBUG_ENTER("JOIN::prepare");
// to prevent double initialization on EXPLAIN
if (optimized)
DBUG_RETURN(0);
conds= conds_init; conds= conds_init;
order= order_init; order= order_init;
group_list= group_init; group_list= group_init;
...@@ -315,8 +321,9 @@ JOIN::prepare(Item ***rref_pointer_array, ...@@ -315,8 +321,9 @@ JOIN::prepare(Item ***rref_pointer_array,
thd->where="having clause"; thd->where="having clause";
thd->allow_sum_func=1; thd->allow_sum_func=1;
select_lex->having_fix_field= 1; select_lex->having_fix_field= 1;
bool having_fix_rc= (having->fix_fields(thd, tables_list, &having) || bool having_fix_rc= !having->fixed &&
having->check_cols(1)); (having->fix_fields(thd, tables_list, &having) ||
having->check_cols(1));
select_lex->having_fix_field= 0; select_lex->having_fix_field= 0;
if (having_fix_rc || thd->net.report_error) if (having_fix_rc || thd->net.report_error)
DBUG_RETURN(-1); /* purecov: inspected */ DBUG_RETURN(-1); /* purecov: inspected */
...@@ -518,7 +525,7 @@ JOIN::optimize() ...@@ -518,7 +525,7 @@ JOIN::optimize()
} }
#endif #endif
conds= optimize_cond(conds,&cond_value); conds= optimize_cond(thd, conds,&cond_value);
if (thd->net.report_error) if (thd->net.report_error)
{ {
error= 1; error= 1;
...@@ -4333,6 +4340,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father, ...@@ -4333,6 +4340,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
SYNPOSIS SYNPOSIS
eliminate_not_funcs() eliminate_not_funcs()
thd thread handler
cond condition tree cond condition tree
DESCRIPTION DESCRIPTION
...@@ -4349,7 +4357,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father, ...@@ -4349,7 +4357,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
New condition tree New condition tree
*/ */
COND *eliminate_not_funcs(COND *cond) COND *eliminate_not_funcs(THD *thd, COND *cond)
{ {
if (!cond) if (!cond)
return cond; return cond;
...@@ -4359,7 +4367,7 @@ COND *eliminate_not_funcs(COND *cond) ...@@ -4359,7 +4367,7 @@ COND *eliminate_not_funcs(COND *cond)
Item *item; Item *item;
while ((item= li++)) while ((item= li++))
{ {
Item *new_item= eliminate_not_funcs(item); Item *new_item= eliminate_not_funcs(thd, item);
if (item != new_item) if (item != new_item)
VOID(li.replace(new_item)); /* replace item with a new condition */ VOID(li.replace(new_item)); /* replace item with a new condition */
} }
...@@ -4367,14 +4375,13 @@ COND *eliminate_not_funcs(COND *cond) ...@@ -4367,14 +4375,13 @@ COND *eliminate_not_funcs(COND *cond)
else if (cond->type() == Item::FUNC_ITEM && /* 'NOT' operation? */ else if (cond->type() == Item::FUNC_ITEM && /* 'NOT' operation? */
((Item_func*) cond)->functype() == Item_func::NOT_FUNC) ((Item_func*) cond)->functype() == Item_func::NOT_FUNC)
{ {
COND *new_cond= ((Item_func*) cond)->arguments()[0]->neg_transformer(); COND *new_cond= ((Item_func*) cond)->arguments()[0]->neg_transformer(thd);
if (new_cond) if (new_cond)
{ {
/* /*
Here we can delete the NOT function. Something like: delete cond; Here we can delete the NOT function. Something like: delete cond;
But we don't need to do it. All items will be deleted later at once. But we don't need to do it. All items will be deleted later at once.
*/ */
new_cond->fix_fields(current_thd, 0, &new_cond);
cond= new_cond; cond= new_cond;
} }
} }
...@@ -4383,7 +4390,7 @@ COND *eliminate_not_funcs(COND *cond) ...@@ -4383,7 +4390,7 @@ COND *eliminate_not_funcs(COND *cond)
static COND * static COND *
optimize_cond(COND *conds,Item::cond_result *cond_value) optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value)
{ {
DBUG_ENTER("optimize_cond"); DBUG_ENTER("optimize_cond");
if (!conds) if (!conds)
...@@ -4393,7 +4400,7 @@ optimize_cond(COND *conds,Item::cond_result *cond_value) ...@@ -4393,7 +4400,7 @@ optimize_cond(COND *conds,Item::cond_result *cond_value)
} }
DBUG_EXECUTE("where",print_where(conds,"original");); DBUG_EXECUTE("where",print_where(conds,"original"););
/* eliminate NOT operators */ /* eliminate NOT operators */
conds= eliminate_not_funcs(conds); conds= eliminate_not_funcs(thd, conds);
DBUG_EXECUTE("where", print_where(conds, "after negation elimination");); DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
/* change field = field to field = const for each found field = const */ /* change field = field to field = const for each found field = const */
propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds); propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds);
...@@ -4402,7 +4409,7 @@ optimize_cond(COND *conds,Item::cond_result *cond_value) ...@@ -4402,7 +4409,7 @@ optimize_cond(COND *conds,Item::cond_result *cond_value)
Remove all and-levels where CONST item != CONST item Remove all and-levels where CONST item != CONST item
*/ */
DBUG_EXECUTE("where",print_where(conds,"after const change");); DBUG_EXECUTE("where",print_where(conds,"after const change"););
conds=remove_eq_conds(conds,cond_value) ; conds= remove_eq_conds(thd, conds, cond_value) ;
DBUG_EXECUTE("info",print_where(conds,"after remove");); DBUG_EXECUTE("info",print_where(conds,"after remove"););
DBUG_RETURN(conds); DBUG_RETURN(conds);
} }
...@@ -4417,7 +4424,7 @@ optimize_cond(COND *conds,Item::cond_result *cond_value) ...@@ -4417,7 +4424,7 @@ optimize_cond(COND *conds,Item::cond_result *cond_value)
*/ */
static COND * static COND *
remove_eq_conds(COND *cond,Item::cond_result *cond_value) remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
{ {
if (cond->type() == Item::COND_ITEM) if (cond->type() == Item::COND_ITEM)
{ {
...@@ -4431,7 +4438,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value) ...@@ -4431,7 +4438,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
Item *item; Item *item;
while ((item=li++)) while ((item=li++))
{ {
Item *new_item=remove_eq_conds(item,&tmp_cond_value); Item *new_item=remove_eq_conds(thd, item, &tmp_cond_value);
if (!new_item) if (!new_item)
li.remove(); li.remove();
else if (item != new_item) else if (item != new_item)
...@@ -4465,7 +4472,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value) ...@@ -4465,7 +4472,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
} }
} }
if (should_fix_fields) if (should_fix_fields)
cond->fix_fields(current_thd,0, &cond); cond->update_used_tables();
if (!((Item_cond*) cond)->argument_list()->elements || if (!((Item_cond*) cond)->argument_list()->elements ||
*cond_value != Item::COND_OK) *cond_value != Item::COND_OK)
...@@ -4492,7 +4499,6 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value) ...@@ -4492,7 +4499,6 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
Item_func_isnull *func=(Item_func_isnull*) cond; Item_func_isnull *func=(Item_func_isnull*) cond;
Item **args= func->arguments(); Item **args= func->arguments();
THD *thd=current_thd;
if (args[0]->type() == Item::FIELD_ITEM) if (args[0]->type() == Item::FIELD_ITEM)
{ {
Field *field=((Item_field*) args[0])->field; Field *field=((Item_field*) args[0])->field;
...@@ -7913,10 +7919,15 @@ find_order_in_list(THD *thd, Item **ref_pointer_array, ...@@ -7913,10 +7919,15 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
} }
order->in_field_list=0; order->in_field_list=0;
Item *it= *order->item; Item *it= *order->item;
if (it->fix_fields(thd, tables, order->item) || /*
//'it' ressigned because fix_field can change it we check it->fixed because Item_func_group_concat can put
(it= *order->item)->check_cols(1) || arguments for which fix_fields already was called
thd->is_fatal_error) */
if (!it->fixed &&
(it->fix_fields(thd, tables, order->item) ||
//'it' ressigned because fix_field can change it
(it= *order->item)->check_cols(1) ||
thd->is_fatal_error))
return 1; // Wrong field return 1; // Wrong field
uint el= all_fields.elements; uint el= all_fields.elements;
all_fields.push_front(it); // Add new field to field list all_fields.push_front(it); // Add new field to field list
......
...@@ -432,4 +432,4 @@ bool cp_buffer_from_ref(TABLE_REF *ref); ...@@ -432,4 +432,4 @@ bool cp_buffer_from_ref(TABLE_REF *ref);
bool error_if_full_join(JOIN *join); bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error); int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab); int safe_index_read(JOIN_TAB *tab);
COND *eliminate_not_funcs(COND *cond); COND *eliminate_not_funcs(THD *thd, COND *cond);
...@@ -203,6 +203,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ...@@ -203,6 +203,8 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
} }
} }
item_list.empty();
// it is not single select
if (first_select->next_select()) if (first_select->next_select())
{ {
union_result->tmp_table_param.field_count= types.elements; union_result->tmp_table_param.field_count= types.elements;
...@@ -222,14 +224,17 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, ...@@ -222,14 +224,17 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
result_table_list.table= table; result_table_list.table= table;
union_result->set_table(table); union_result->set_table(table);
item_list.empty();
thd_arg->lex->current_select= lex_select_save; thd_arg->lex->current_select= lex_select_save;
{ {
Field **field; Field **field;
for (field= table->field; *field; field++) for (field= table->field; *field; field++)
{ {
if (item_list.push_back(new Item_field(*field))) Item_field *item= new Item_field(*field);
if (item_list.push_back(item))
DBUG_RETURN(-1); DBUG_RETURN(-1);
#ifndef DBUG_OFF
item->double_fix= 0;
#endif
} }
} }
} }
......
...@@ -8206,7 +8206,6 @@ static void test_bug2247() ...@@ -8206,7 +8206,6 @@ static void test_bug2247()
} }
static void test_subqueries() static void test_subqueries()
{ {
MYSQL_STMT *stmt; MYSQL_STMT *stmt;
...@@ -8346,6 +8345,37 @@ static void test_bug2248() ...@@ -8346,6 +8345,37 @@ static void test_bug2248()
myquery(rc); myquery(rc);
} }
static void test_subqueries_ref()
{
MYSQL_STMT *stmt;
int rc, i;
const char *query= "SELECT a as ccc from t1 where a+1=(SELECT 1+ccc from t1 where ccc+1=a+1 and a=1)";
myheader("test_subquery_ref");
rc = mysql_query(mysql, "DROP TABLE IF EXISTS t1");
myquery(rc);
rc= mysql_query(mysql,"CREATE TABLE t1 (a int);");
myquery(rc);
rc= mysql_query(mysql,
"insert into t1 values (1), (2), (3), (4), (5);");
myquery(rc);
stmt= mysql_prepare(mysql, query, strlen(query));
mystmt_init(stmt);
for (i= 0; i < 3; i++)
{
rc= mysql_execute(stmt);
mystmt(stmt, rc);
assert(1 == my_process_stmt_result(stmt));
}
mysql_stmt_close(stmt);
rc= mysql_query(mysql, "DROP TABLE t1");
myquery(rc);
}
/* /*
Read and parse arguments and MySQL options from my.cnf Read and parse arguments and MySQL options from my.cnf
...@@ -8602,6 +8632,9 @@ int main(int argc, char **argv) ...@@ -8602,6 +8632,9 @@ int main(int argc, char **argv)
test_subqueries(); /* repeatable subqueries */ test_subqueries(); /* repeatable subqueries */
test_bad_union(); /* correct setup of UNION */ test_bad_union(); /* correct setup of UNION */
test_distinct(); /* distinct aggregate functions */ test_distinct(); /* distinct aggregate functions */
test_subqueries_ref(); /* outer reference in subqueries converted
Item_field -> Item_ref */
end_time= time((time_t *)0); end_time= time((time_t *)0);
......
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