Commit 481cd2db authored by unknown's avatar unknown

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.
parent 2038256b
......@@ -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;
......
......@@ -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;
......
......@@ -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,
......
......@@ -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;
......
......@@ -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)));
......
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