diff options
author | unknown <sanja@askmonty.org> | 2011-01-24 13:31:17 +0200 |
---|---|---|
committer | unknown <sanja@askmonty.org> | 2011-01-24 13:31:17 +0200 |
commit | 481cd2dbf1312f60d320598ee7a40ecb77da1930 (patch) | |
tree | d88616229c2a15b35c8d49a2ecc0a4ec4258ac1e /sql | |
parent | 2038256bede201f025cac384a9043627a83afd5d (diff) | |
download | mariadb-git-481cd2dbf1312f60d320598ee7a40ecb77da1930.tar.gz |
Fix of problem with WHERE/HAVING consist of alone outer reference field by wrapping it.
sql/item.cc:
Wrapper added.
sql/item.h:
Wrapper added.
sql/mysql_priv.h:
Wrap function added.
sql/sql_base.cc:
Wrap function added.
Fix of problem with WHERE consist of alone outer reference field by wrapping it.
sql/sql_select.cc:
Fix of problem with HAVING consist of alone outer reference field by wrapping it.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 34 | ||||
-rw-r--r-- | sql/item.h | 41 | ||||
-rw-r--r-- | sql/mysql_priv.h | 1 | ||||
-rw-r--r-- | sql/sql_base.cc | 29 | ||||
-rw-r--r-- | sql/sql_select.cc | 7 |
5 files changed, 110 insertions, 2 deletions
diff --git a/sql/item.cc b/sql/item.cc index 188200bd7bd..a3a80ab6777 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -6619,6 +6619,40 @@ bool Item_direct_ref::get_date(MYSQL_TIME *ltime,uint fuzzydate) } +Item* Item_direct_ref_to_ident::transform(Item_transformer transformer, + uchar *argument) +{ + DBUG_ASSERT(!current_thd->is_stmt_prepare()); + + Item *new_item= ident->transform(transformer, argument); + if (!new_item) + return 0; + DBUG_ASSERT(new_item->type() == FIELD_ITEM || new_item->type() == REF_ITEM); + + if (ident != new_item) + current_thd->change_item_tree((Item**)&ident, new_item); + return (this->*transformer)(argument); +} + + +Item* Item_direct_ref_to_ident::compile(Item_analyzer analyzer, uchar **arg_p, + Item_transformer transformer, + uchar *arg_t) +{ + if (!(this->*analyzer)(arg_p)) + return 0; + + uchar *arg_v= *arg_p; + Item *new_item= ident->compile(analyzer, &arg_v, transformer, arg_t); + if (new_item && ident != new_item) + { + DBUG_ASSERT(new_item->type() == FIELD_ITEM || new_item->type() == REF_ITEM); + current_thd->change_item_tree((Item**)&ident, new_item); + } + return (this->*transformer)(arg_t); +} + + Item_cache_wrapper::~Item_cache_wrapper() { delete expr_cache; diff --git a/sql/item.h b/sql/item.h index f78f25bb9d2..76df608ab29 100644 --- a/sql/item.h +++ b/sql/item.h @@ -518,7 +518,7 @@ public: SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER, PARAM_ITEM, TRIGGER_FIELD_ITEM, DECIMAL_ITEM, XPATH_NODESET, XPATH_NODESET_CMP, - VIEW_FIXER_ITEM, EXPR_CACHE_ITEM}; + VIEW_FIXER_ITEM, EXPR_CACHE_ITEM, UNKNOWN_ITEM}; enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE }; @@ -612,7 +612,7 @@ public: virtual Item_result cast_to_int_type() const { return result_type(); } virtual enum_field_types string_field_type() const; virtual enum_field_types field_type() const; - virtual enum Type type() const =0; + virtual enum Type type() const { return UNKNOWN_ITEM; }; /* Return information about function monotonicity. See comment for @@ -2609,6 +2609,43 @@ public: virtual Ref_Type ref_type() { return DIRECT_REF; } }; + +/** + This class is the same as Item_direct_ref but created to wrap Item_ident + before fix_fields() call +*/ + +class Item_direct_ref_to_ident :public Item_direct_ref +{ + Item_ident *ident; +public: + Item_direct_ref_to_ident(Item_ident *item) + :Item_direct_ref(item->context, (Item**)&item, item->table_name, item->field_name, + FALSE) + { + ident= item; + ref= (Item**)&ident; + } + + bool fix_fields(THD *thd, Item **it) + { + DBUG_ASSERT(ident->type() == FIELD_ITEM || ident->type() == REF_ITEM); + if ((!ident->fixed && ident->fix_fields(thd, ref)) || + ident->check_cols(1)) + return TRUE; + set_properties(); + return FALSE; + } + + virtual void print(String *str, enum_query_type query_type) + { ident->print(str, query_type); } + + virtual Item* transform(Item_transformer transformer, uchar *arg); + virtual Item* compile(Item_analyzer analyzer, uchar **arg_p, + Item_transformer transformer, uchar *arg_t); +}; + + class Expression_cache; class Item_cache; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index efc1a70b9fe..a251c1d9bf9 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -1612,6 +1612,7 @@ inline bool setup_fields_with_no_wrap(THD *thd, Item **ref_pointer_array, } int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, COND **conds); +void wrap_ident(THD *thd, Item **conds); int setup_ftfuncs(SELECT_LEX* select); int init_ftfuncs(THD *thd, SELECT_LEX* select, bool no_order); void wait_for_condition(THD *thd, pthread_mutex_t *mutex, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 530ebf85955..19a3ddb88ae 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -8120,6 +8120,29 @@ insert_fields(THD *thd, Name_resolution_context *context, const char *db_name, } +/** + Wrap Item_ident + + @param thd thread handle + @param conds pointer to the condition which should be wrapped +*/ + +void wrap_ident(THD *thd, Item **conds) +{ + Item_direct_ref_to_ident *wrapper; + DBUG_ASSERT((*conds)->type() == Item::FIELD_ITEM || (*conds)->type() == Item::REF_ITEM); + Query_arena *arena= thd->stmt_arena, backup; + if (arena->is_conventional()) + arena= 0; + else + thd->set_n_backup_active_arena(arena, &backup); + if ((wrapper= new Item_direct_ref_to_ident((Item_ident *)(*conds)))) + (*conds)= (Item*) wrapper; + if (arena) + thd->restore_active_arena(arena, &backup); +} + + /* Fix all conditions and outer join expressions. @@ -8183,6 +8206,12 @@ int setup_conds(THD *thd, TABLE_LIST *tables, TABLE_LIST *leaves, print_where(*conds, "WHERE in setup_conds", QT_ORDINARY);); + /* + Wrap alone field in WHERE clause in case it will be outer field of subquery + which need persistent pointer on it, but conds could be changed by optimizer + */ + if ((*conds)->type() == Item::FIELD_ITEM) + wrap_ident(thd, conds); if ((!(*conds)->fixed && (*conds)->fix_fields(thd, conds)) || (*conds)->check_cols(1)) goto err_no_arena; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 462cbbce4cb..e1dfb4a3519 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -543,6 +543,13 @@ JOIN::prepare(Item ***rref_pointer_array, thd->where="having clause"; thd->lex->allow_sum_func|= 1 << select_lex_arg->nest_level; select_lex->having_fix_field= 1; + /* + Wrap alone field in HAVING clause in case it will be outer field of subquery + which need persistent pointer on it, but having could be changed by optimizer + */ + if (having->type() == Item::REF_ITEM && + ((Item_ref *)having)->ref_type() == Item_ref::REF) + wrap_ident(thd, &having); bool having_fix_rc= (!having->fixed && (having->fix_fields(thd, &having) || having->check_cols(1))); |