summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbell@sanja.is.com.ua <>2004-03-17 14:26:26 +0200
committerbell@sanja.is.com.ua <>2004-03-17 14:26:26 +0200
commit8035ce40eca47844ecda29d48e84639f9c9334d9 (patch)
tree879e13469f1915539666e702fc32401e7f3a61d2
parentb8c065c527846fdeb0122e26d3fc20731e28ca4f (diff)
downloadmariadb-git-8035ce40eca47844ecda29d48e84639f9c9334d9.tar.gz
DBUG_ASSERT(fixed == 0) added to fix_fields()
-rw-r--r--sql/item.cc50
-rw-r--r--sql/item.h31
-rw-r--r--sql/item_cmpfunc.cc136
-rw-r--r--sql/item_cmpfunc.h29
-rw-r--r--sql/item_func.cc5
-rw-r--r--sql/item_func.h2
-rw-r--r--sql/item_row.cc2
-rw-r--r--sql/item_strfunc.h2
-rw-r--r--sql/item_subselect.cc11
-rw-r--r--sql/item_sum.cc5
-rw-r--r--sql/item_sum.h1
-rw-r--r--sql/item_uniq.h1
-rw-r--r--sql/sql_base.cc9
-rw-r--r--sql/sql_derived.cc6
-rw-r--r--sql/sql_select.cc51
-rw-r--r--sql/sql_select.h2
-rw-r--r--sql/sql_union.cc9
-rw-r--r--tests/client_test.c35
18 files changed, 292 insertions, 95 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 45cd85d1775..c0eff7e85c2 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -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),
- db_name(item->db_name),
- table_name(item->table_name),
- field_name(item->field_name),
- depended_from(item->depended_from)
+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;
diff --git a/sql/item.h b/sql/item.h
index 832fc775016..27f427c1ef4 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -233,7 +233,7 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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);
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index ac1af32388f..23213c8009b 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -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;
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 9d39ddf4e76..463bb215da4 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -218,6 +218,8 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
}
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ public:
item->copy_andor_arguments(thd, this);
return item;
}
- Item *neg_transformer();
+ Item *neg_transformer(THD *thd);
};
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 88c2bf824c6..c8d4178e739 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -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
diff --git a/sql/item_func.h b/sql/item_func.h
index 8fbe5a124da..b463be1e0ca 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -765,6 +765,7 @@ public:
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 @@ public:
void cleanup()
{
DBUG_ENTER("Item_func_match");
+ Item_real_func::cleanup();
if (!master && ft_handler)
{
ft_handler->please->close_search(ft_handler);
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 2b0cd38e3c1..c7e4bc0acf4 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -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;
}
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index 5b9c442b5db..74b66d37491 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -100,6 +100,7 @@ public:
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 @@ public:
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));
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index deb1ebabef9..90070e21953 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -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;
@@ -125,8 +126,10 @@ bool Item_subselect::fix_fields(THD *thd_param, TABLE_LIST *tables, Item **ref)
engine->exclude();
substitution= 0;
fixed= 1;
- thd->where= "checking transformed subquery";
- int ret= (*ref)->fix_fields(thd, tables, ref);
+ thd->where= "checking transformed subquery";
+ 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);
}
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index 77a910ae5d6..97fd8afb25e 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -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)
diff --git a/sql/item_sum.h b/sql/item_sum.h
index 11c95100db5..41d700b0ff8 100644
--- a/sql/item_sum.h
+++ b/sql/item_sum.h
@@ -533,6 +533,7 @@ public:
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);
}
diff --git a/sql/item_uniq.h b/sql/item_uniq.h
index 47f967b52c6..5de4b82a99d 100644
--- a/sql/item_uniq.h
+++ b/sql/item_uniq.h
@@ -48,6 +48,7 @@ public:
void update_field() {}
bool fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
{
+ DBUG_ASSERT(fixed == 0);
fixed= 1;
return 0;
}
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index bdbb14f0819..a2f13c47694 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -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++;
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index 0e04316a2e7..4bfb8cdfe3c 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -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;
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 00b573922fe..cc9f453e595 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -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,8 +321,9 @@ 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) ||
- having->check_cols(1));
+ 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)
DBUG_RETURN(-1); /* purecov: inspected */
@@ -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) ||
- //'it' ressigned because fix_field can change it
- (it= *order->item)->check_cols(1) ||
- thd->is_fatal_error)
+ /*
+ 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))
return 1; // Wrong field
uint el= all_fields.elements;
all_fields.push_front(it); // Add new field to field list
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 36526bee066..fea3f7c6b80 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -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);
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index a05fa44cfc9..d45b867b197 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -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
}
}
}
diff --git a/tests/client_test.c b/tests/client_test.c
index fae8c3cd54d..31a53f6d81e 100644
--- a/tests/client_test.c
+++ b/tests/client_test.c
@@ -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);