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)
Item_ident::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),
:changed_during_fix_field(0), db_name(db_name_par),
table_name(table_name_par), field_name(field_name_par),
depended_from(0)
{
name = (char*) field_name_par;
}
// Constructor used by Item_field & Item_ref (see Item comment)
Item_ident::Item_ident(THD *thd, Item_ident *item):
Item(thd, item),
Item_ident::Item_ident(THD *thd, Item_ident *item)
:Item(thd, item),
changed_during_fix_field(0),
db_name(item->db_name),
table_name(item->table_name),
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)
{
DBUG_ENTER("Item_ident::remove_dependence_processor");
......@@ -289,11 +301,14 @@ bool DTCollation::aggregate(DTCollation &dt)
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);
collation.set(DERIVATION_IMPLICIT);
fixed= 1; // This item is not needed in fix_fields
}
// Constructor need to process subselect with temporary tables (see Item)
......@@ -301,6 +316,9 @@ Item_field::Item_field(THD *thd, Item_field *item)
:Item_ident(thd, item),
field(item->field),
result_field(item->result_field)
#ifndef DBUG_OFF
,double_fix(0)
#endif
{
collation.set(DERIVATION_IMPLICIT);
}
......@@ -786,6 +804,9 @@ bool Item::fix_fields(THD *thd,
struct st_table_list *list,
Item ** ref)
{
// We do not check fields which are fixed during construction
DBUG_ASSERT(fixed == 0 || type() == INT_ITEM || type() == CACHE_ITEM);
fixed= 1;
return 0;
}
......@@ -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)
{
DBUG_ASSERT(fixed == 0 || double_fix == 0);
if (!field) // If field is not checked
{
TABLE_LIST *where= 0;
......@@ -952,6 +974,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
ref,
(char *)table_name,
(char *)field_name);
register_item_tree_changing(ref);
if (!rf)
return 1;
/*
......@@ -1005,6 +1028,11 @@ void Item_field::cleanup()
{
DBUG_ENTER("Item_field::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;
DBUG_VOID_RETURN;
}
......@@ -1480,6 +1508,7 @@ bool Item_field::send(Protocol *protocol, String *buffer)
bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
DBUG_ASSERT(fixed == 0);
uint counter;
if (!ref)
{
......@@ -1585,6 +1614,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
Item_field* fld;
if (!((*reference)= fld= new Item_field(tmp)))
return 1;
register_item_tree_changing(reference);
mark_as_dependent(thd, last, thd->lex->current_select, fld);
return 0;
}
......@@ -1696,6 +1726,7 @@ bool Item_default_value::fix_fields(THD *thd,
struct st_table_list *table_list,
Item **items)
{
DBUG_ASSERT(fixed == 0);
if (!arg)
return 0;
if (arg->fix_fields(thd, table_list, &arg))
......@@ -1744,6 +1775,7 @@ bool Item_insert_value::fix_fields(THD *thd,
struct st_table_list *table_list,
Item **items)
{
DBUG_ASSERT(fixed == 0);
if (arg->fix_fields(thd, table_list, &arg))
return 1;
......
......@@ -233,7 +233,7 @@ class Item {
Field *tmp_table_field_from_field_type(TABLE *table);
/* 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()
{
cleanup();
......@@ -245,6 +245,7 @@ class Item {
class st_select_lex;
class Item_ident :public Item
{
Item **changed_during_fix_field;
public:
const char *db_name;
const char *table_name;
......@@ -254,7 +255,9 @@ class Item_ident :public Item
const char *field_name_par);
Item_ident(THD *thd, Item_ident *item);
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);
};
......@@ -264,11 +267,17 @@ class Item_field :public Item_ident
void set_field(Field *field);
public:
Field *field,*result_field;
// Item_field() {}
#ifndef DBUG_OFF
bool double_fix;
#endif
Item_field(const char *db_par,const char *table_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); }
// Constructor need to process subselect with temporary tables (see Item)
Item_field(THD *thd, Item_field *item);
......@@ -324,6 +333,7 @@ class Item_null :public Item
enum_field_types field_type() const { return MYSQL_TYPE_NULL; }
bool fix_fields(THD *thd, struct st_table_list *list, Item **item)
{
DBUG_ASSERT(fixed == 0);
bool res= Item::fix_fields(thd, list, item);
max_length=0;
return res;
......@@ -413,7 +423,8 @@ class Item_int :public Item
int save_in_field(Field *field, bool no_conversions);
bool basic_const_item() const { return 1; }
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);
};
......@@ -422,14 +433,17 @@ class Item_uint :public Item_int
{
public:
Item_uint(const char *str_arg, uint length) :
Item_int(str_arg, (longlong) strtoull(str_arg,(char**) 0,10), length) {}
Item_uint(uint32 i) :Item_int((longlong) i, 10) {}
Item_int(str_arg, (longlong) strtoull(str_arg,(char**) 0,10), length)
{ fixed= 0; }
Item_uint(uint32 i) :Item_int((longlong) i, 10)
{ fixed= 0; }
double val() { return ulonglong2double((ulonglong)value); }
String *val_str(String*);
Item *new_item() { return new Item_uint(name,max_length); }
int save_in_field(Field *field, bool no_conversions);
bool fix_fields(THD *thd, struct st_table_list *list, Item **item)
{
DBUG_ASSERT(fixed == 0);
bool res= Item::fix_fields(thd, list, item);
unsigned_flag= 1;
return res;
......@@ -903,7 +917,8 @@ class Item_cache: public Item
static Item_cache* get_cache(Item_result type);
table_map used_tables() const { return used_table_map; }
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);
};
......
......@@ -502,7 +502,6 @@ bool Item_in_optimizer::fix_left(THD *thd,
not_null_tables_cache= args[0]->not_null_tables();
with_sum_func= args[0]->with_sum_func;
const_item_cache= args[0]->const_item();
fixed= 1;
return 0;
}
......@@ -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,
Item ** ref)
{
if (fix_left(thd, tables, ref))
DBUG_ASSERT(fixed == 0);
if (!args[0]->fixed && fix_left(thd, tables, ref))
return 1;
if (args[0]->maybe_null)
maybe_null=1;
......@@ -529,6 +529,7 @@ bool Item_in_optimizer::fix_fields(THD *thd, struct st_table_list *tables,
used_tables_cache|= args[1]->used_tables();
not_null_tables_cache|= args[1]->not_null_tables();
const_item_cache&= args[1]->const_item();
fixed= 1;
return 0;
}
......@@ -1755,6 +1756,7 @@ void Item_cond::copy_andor_arguments(THD *thd, Item_cond *item)
bool
Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
List_iterator<Item> li(list);
Item *item;
#ifndef EMBEDDED_LIBRARY
......@@ -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);
Item *item;
while ((item= li++)) /* Apply not transformation to the arguments */
{
Item *new_item= item->neg_transformer();
VOID(li.replace(new_item ? new_item : new Item_func_not(item)));
Item *new_item= item->neg_transformer(thd);
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
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))
return 1;
......@@ -2150,6 +2166,7 @@ bool Item_func_like::fix_fields(THD *thd, TABLE_LIST *tlist, Item ** ref)
bool
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) ||
args[1]->fix_fields(thd,tables, args + 1) || args[1]->check_cols(1))
return 1; /* purecov: inspected */
......@@ -2518,6 +2535,7 @@ longlong Item_cond_xor::val_int()
SYNPOSIS
neg_transformer()
thd thread handler
DESCRIPTION
Transform the item using next rules:
......@@ -2541,62 +2559,116 @@ longlong Item_cond_xor::val_int()
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 */
return eliminate_not_funcs(args[0]);
// We should apply negation elimination to the argument of the NOT function
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_cond_or(list);
return new Item_func_lt(args[0], args[1]);
}
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_cond_and(list);
return new Item_func_le(args[0], args[1]);
}
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
tmp_arg[1]= orig_b;
DBUG_VOID_RETURN;
}
Item *neg_transformer(THD *thd);
virtual Item *negated_item();
};
class Item_func_not :public Item_bool_func
......@@ -227,7 +229,7 @@ class Item_func_not :public Item_bool_func
longlong val_int();
enum Functype functype() const { return NOT_FUNC; }
const char *func_name() const { return "not"; }
Item *neg_transformer();
Item *neg_transformer(THD *thd);
};
class Item_func_not_all :public Item_func_not
......@@ -254,7 +256,7 @@ class Item_func_eq :public Item_bool_rowready_func2
enum Functype rev_functype() const { return EQ_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return "="; }
Item *neg_transformer();
Item *negated_item();
};
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; }
cond_result eq_cmp_result() const { return COND_TRUE; }
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
enum Functype rev_functype() const { return LE_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; }
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
enum Functype rev_functype() const { return LT_FUNC; }
cond_result eq_cmp_result() const { return COND_FALSE; }
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
enum Functype rev_functype() const { return GE_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; }
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
enum Functype rev_functype() const { return GT_FUNC; }
cond_result eq_cmp_result() const { return COND_FALSE; }
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
cond_result eq_cmp_result() const { return COND_FALSE; }
optimize_type select_optimize() const { return OPTIMIZE_KEY; }
const char *func_name() const { return "<>"; }
Item *neg_transformer();
Item *negated_item();
};
......@@ -409,6 +412,7 @@ class Item_func_if :public Item_func
enum Item_result result_type () const { return cached_result_type; }
bool fix_fields(THD *thd,struct st_table_list *tlist, Item **ref)
{
DBUG_ASSERT(fixed == 0);
args[0]->top_level_item();
return Item_func::fix_fields(thd, tlist, ref);
}
......@@ -726,6 +730,7 @@ class Item_func_in :public Item_int_func
void cleanup()
{
DBUG_ENTER("Item_func_in::cleanup");
Item_int_func::cleanup();
delete array;
delete in_item;
array= 0;
......@@ -778,7 +783,7 @@ class Item_func_isnull :public Item_bool_func
}
table_map not_null_tables() const { return 0; }
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; }
};
......@@ -812,7 +817,7 @@ class Item_func_isnotnull :public Item_bool_func
const char *func_name() const { return "isnotnull"; }
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
table_map not_null_tables() const { return 0; }
Item *neg_transformer();
Item *neg_transformer(THD *thd);
void print(String *str);
CHARSET_INFO *compare_collation() { return args[0]->collation.collation; }
};
......@@ -920,7 +925,7 @@ class Item_cond :public Item_bool_func
void top_level_item() { abort_on_null=1; }
void copy_andor_arguments(THD *thd, Item_cond *item);
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
item->copy_andor_arguments(thd, this);
return item;
}
Item *neg_transformer();
Item *neg_transformer(THD *thd);
};
class Item_cond_or :public Item_cond
......@@ -962,7 +967,7 @@ class Item_cond_or :public Item_cond
item->copy_andor_arguments(thd, this);
return item;
}
Item *neg_transformer();
Item *neg_transformer(THD *thd);
};
......
......@@ -199,6 +199,7 @@ Item_func::Item_func(THD *thd, Item_func *item)
bool
Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
Item **arg,**arg_end;
#ifndef EMBEDDED_LIBRARY // Avoid compiler warning
char buff[STACK_BUFF_ALLOC]; // Max argument in function
......@@ -215,7 +216,7 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
Item *item;
/* 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))
return 1; /* purecov: inspected */
item= *arg;
......@@ -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,
Item **ref)
{
DBUG_ASSERT(fixed == 0);
/* fix_fields will call Item_func_set_user_var::fix_length_and_dec */
if (Item_func::fix_fields(thd, tables, ref) ||
!(entry= get_variable(&thd->user_vars, name, 1)))
......@@ -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)
{
DBUG_ASSERT(fixed == 0);
Item *item;
LINT_INIT(item); // Safe as arg_count is > 1
......
......@@ -765,6 +765,7 @@ class Item_udf_func :public Item_func
const char *func_name() const { return udf.name(); }
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);
used_tables_cache= udf.used_tables_cache;
const_item_cache= udf.const_item_cache;
......@@ -1000,6 +1001,7 @@ class Item_func_match :public Item_real_func
void cleanup()
{
DBUG_ENTER("Item_func_match");
Item_real_func::cleanup();
if (!master && ft_handler)
{
ft_handler->please->close_search(ft_handler);
......
......@@ -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)
{
DBUG_ASSERT(fixed == 0);
null_value= 0;
maybe_null= 0;
Item **arg, **arg_end;
......@@ -78,6 +79,7 @@ bool Item_row::fix_fields(THD *thd, TABLE_LIST *tabl, Item **ref)
maybe_null|= item->maybe_null;
with_sum_func= with_sum_func || item->with_sum_func;
}
fixed= 1;
return 0;
}
......
......@@ -100,6 +100,7 @@ class Item_func_concat_ws :public Item_str_func
void update_used_tables();
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
DBUG_ASSERT(fixed == 0);
return (separator->fix_fields(thd, tlist, &separator) ||
separator->check_cols(1) ||
Item_func::fix_fields(thd, tlist, ref));
......@@ -411,6 +412,7 @@ class Item_func_make_set :public Item_str_func
String *val_str(String *str);
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
DBUG_ASSERT(fixed == 0);
return (item->fix_fields(thd, tlist, &item) ||
item->check_cols(1) ||
Item_func::fix_fields(thd, tlist, ref));
......
......@@ -102,6 +102,7 @@ Item_subselect::select_transformer(JOIN *join)
bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
engine->set_thd((thd= thd_param));
stmt= thd->current_statement;
......@@ -126,7 +127,9 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
substitution= 0;
fixed= 1;
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)))
if ((*ref)->with_sum_func)
{
......@@ -651,9 +654,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
select_lex->item_list.empty();
select_lex->item_list.push_back(item);
if (item->fix_fields(thd, join->tables_list,
select_lex->item_list.head_ref()))
goto err;
// fix_fields call for 'item' will be made during new subquery fix_fields
subs= new Item_singlerow_subselect(select_lex);
}
......
......@@ -162,6 +162,7 @@ Item_sum_int::val_str(String *str)
bool
Item_sum_num::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
if (!thd->allow_sum_func)
{
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)
bool
Item_sum_hybrid::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
Item *item= args[0];
if (!thd->allow_sum_func)
{
......@@ -1116,6 +1118,7 @@ void Item_sum_count_distinct::cleanup()
bool Item_sum_count_distinct::fix_fields(THD *thd, TABLE_LIST *tables,
Item **ref)
{
DBUG_ASSERT(fixed == 0);
if (Item_sum_num::fix_fields(thd, tables, ref))
return 1;
return 0;
......@@ -1679,6 +1682,7 @@ Item_func_group_concat::Item_func_group_concat(bool is_distinct,
void 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
to original item from which was made copy => it own its objects )
......@@ -1794,6 +1798,7 @@ void Item_func_group_concat::reset_field()
bool
Item_func_group_concat::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
uint i; /* for loop variable */
if (!thd->allow_sum_func)
......
......@@ -533,6 +533,7 @@ class Item_udf_sum : public Item_sum
const char *func_name() const { return udf.name(); }
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
DBUG_ASSERT(fixed == 0);
fixed= 1;
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
void update_field() {}
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
DBUG_ASSERT(fixed == 0);
fixed= 1;
return 0;
}
......
......@@ -2140,7 +2140,7 @@ int setup_fields(THD *thd, Item **ref_pointer_array, TABLE_LIST *tables,
Item **ref= ref_pointer_array;
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))
DBUG_RETURN(-1); /* purecov: inspected */
if (ref)
......@@ -2322,7 +2322,8 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
if (*conds)
{
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);
not_null_tables= (*conds)->not_null_tables();
}
......@@ -2334,7 +2335,9 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
{
/* Make a join an a expression */
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))
DBUG_RETURN(1);
thd->lex->current_select->cond_count++;
......
......@@ -151,7 +151,11 @@ static int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit,
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
{
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,
uint select_options, const char *info,
Item *having, Procedure *proc,
SELECT_LEX_UNIT *unit);
static COND *optimize_cond(COND *conds,Item::cond_result *cond_value);
static COND *remove_eq_conds(COND *cond,Item::cond_result *cond_value);
static COND *optimize_cond(THD *thd, COND *conds,
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 open_tmp_table(TABLE *table);
static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
......@@ -286,6 +288,10 @@ JOIN::prepare(Item ***rref_pointer_array,
{
DBUG_ENTER("JOIN::prepare");
// to prevent double initialization on EXPLAIN
if (optimized)
DBUG_RETURN(0);
conds= conds_init;
order= order_init;
group_list= group_init;
......@@ -315,7 +321,8 @@ JOIN::prepare(Item ***rref_pointer_array,
thd->where="having clause";
thd->allow_sum_func=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->fix_fields(thd, tables_list, &having) ||
having->check_cols(1));
select_lex->having_fix_field= 0;
if (having_fix_rc || thd->net.report_error)
......@@ -518,7 +525,7 @@ JOIN::optimize()
}
#endif
conds= optimize_cond(conds,&cond_value);
conds= optimize_cond(thd, conds,&cond_value);
if (thd->net.report_error)
{
error= 1;
......@@ -4333,6 +4340,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
SYNPOSIS
eliminate_not_funcs()
thd thread handler
cond condition tree
DESCRIPTION
......@@ -4349,7 +4357,7 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
New condition tree
*/
COND *eliminate_not_funcs(COND *cond)
COND *eliminate_not_funcs(THD *thd, COND *cond)
{
if (!cond)
return cond;
......@@ -4359,7 +4367,7 @@ COND *eliminate_not_funcs(COND *cond)
Item *item;
while ((item= li++))
{
Item *new_item= eliminate_not_funcs(item);
Item *new_item= eliminate_not_funcs(thd, item);
if (item != new_item)
VOID(li.replace(new_item)); /* replace item with a new condition */
}
......@@ -4367,14 +4375,13 @@ COND *eliminate_not_funcs(COND *cond)
else if (cond->type() == Item::FUNC_ITEM && /* 'NOT' operation? */
((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)
{
/*
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.
*/
new_cond->fix_fields(current_thd, 0, &new_cond);
cond= new_cond;
}
}
......@@ -4383,7 +4390,7 @@ COND *eliminate_not_funcs(COND *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");
if (!conds)
......@@ -4393,7 +4400,7 @@ optimize_cond(COND *conds,Item::cond_result *cond_value)
}
DBUG_EXECUTE("where",print_where(conds,"original"););
/* eliminate NOT operators */
conds= eliminate_not_funcs(conds);
conds= eliminate_not_funcs(thd, conds);
DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
/* change field = field to field = const for each found field = const */
propagate_cond_constants((I_List<COND_CMP> *) 0,conds,conds);
......@@ -4402,7 +4409,7 @@ optimize_cond(COND *conds,Item::cond_result *cond_value)
Remove all and-levels where CONST item != CONST item
*/
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_RETURN(conds);
}
......@@ -4417,7 +4424,7 @@ optimize_cond(COND *conds,Item::cond_result *cond_value)
*/
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)
{
......@@ -4431,7 +4438,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
Item *item;
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)
li.remove();
else if (item != new_item)
......@@ -4465,7 +4472,7 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
}
}
if (should_fix_fields)
cond->fix_fields(current_thd,0, &cond);
cond->update_used_tables();
if (!((Item_cond*) cond)->argument_list()->elements ||
*cond_value != Item::COND_OK)
......@@ -4492,7 +4499,6 @@ remove_eq_conds(COND *cond,Item::cond_result *cond_value)
Item_func_isnull *func=(Item_func_isnull*) cond;
Item **args= func->arguments();
THD *thd=current_thd;
if (args[0]->type() == Item::FIELD_ITEM)
{
Field *field=((Item_field*) args[0])->field;
......@@ -7913,10 +7919,15 @@ find_order_in_list(THD *thd, Item **ref_pointer_array,
}
order->in_field_list=0;
Item *it= *order->item;
if (it->fix_fields(thd, tables, order->item) ||
/*
we check it->fixed because Item_func_group_concat can put
arguments for which fix_fields already was called
*/
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)
thd->is_fatal_error))
return 1; // Wrong field
uint el= all_fields.elements;
all_fields.push_front(it); // Add new field to field list
......
......@@ -432,4 +432,4 @@ bool cp_buffer_from_ref(TABLE_REF *ref);
bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error);
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,
}
}
item_list.empty();
// it is not single select
if (first_select->next_select())
{
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,
result_table_list.table= table;
union_result->set_table(table);
item_list.empty();
thd_arg->lex->current_select= lex_select_save;
{
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);
#ifndef DBUG_OFF
item->double_fix= 0;
#endif
}
}
}
......
......@@ -8206,7 +8206,6 @@ static void test_bug2247()
}
static void test_subqueries()
{
MYSQL_STMT *stmt;
......@@ -8346,6 +8345,37 @@ static void test_bug2248()
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
......@@ -8602,6 +8632,9 @@ int main(int argc, char **argv)
test_subqueries(); /* repeatable subqueries */
test_bad_union(); /* correct setup of UNION */
test_distinct(); /* distinct aggregate functions */
test_subqueries_ref(); /* outer reference in subqueries converted
Item_field -> Item_ref */
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