diff options
author | bell@sanja.is.com.ua <> | 2004-03-17 14:26:26 +0200 |
---|---|---|
committer | bell@sanja.is.com.ua <> | 2004-03-17 14:26:26 +0200 |
commit | 8035ce40eca47844ecda29d48e84639f9c9334d9 (patch) | |
tree | 879e13469f1915539666e702fc32401e7f3a61d2 | |
parent | b8c065c527846fdeb0122e26d3fc20731e28ca4f (diff) | |
download | mariadb-git-8035ce40eca47844ecda29d48e84639f9c9334d9.tar.gz |
DBUG_ASSERT(fixed == 0) added to fix_fields()
-rw-r--r-- | sql/item.cc | 50 | ||||
-rw-r--r-- | sql/item.h | 31 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 136 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 29 | ||||
-rw-r--r-- | sql/item_func.cc | 5 | ||||
-rw-r--r-- | sql/item_func.h | 2 | ||||
-rw-r--r-- | sql/item_row.cc | 2 | ||||
-rw-r--r-- | sql/item_strfunc.h | 2 | ||||
-rw-r--r-- | sql/item_subselect.cc | 11 | ||||
-rw-r--r-- | sql/item_sum.cc | 5 | ||||
-rw-r--r-- | sql/item_sum.h | 1 | ||||
-rw-r--r-- | sql/item_uniq.h | 1 | ||||
-rw-r--r-- | sql/sql_base.cc | 9 | ||||
-rw-r--r-- | sql/sql_derived.cc | 6 | ||||
-rw-r--r-- | sql/sql_select.cc | 51 | ||||
-rw-r--r-- | sql/sql_select.h | 2 | ||||
-rw-r--r-- | sql/sql_union.cc | 9 | ||||
-rw-r--r-- | tests/client_test.c | 35 |
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); |