summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <sanja@askmonty.org>2011-01-24 13:31:17 +0200
committerunknown <sanja@askmonty.org>2011-01-24 13:31:17 +0200
commit481cd2dbf1312f60d320598ee7a40ecb77da1930 (patch)
treed88616229c2a15b35c8d49a2ecc0a4ec4258ac1e /sql
parent2038256bede201f025cac384a9043627a83afd5d (diff)
downloadmariadb-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.cc34
-rw-r--r--sql/item.h41
-rw-r--r--sql/mysql_priv.h1
-rw-r--r--sql/sql_base.cc29
-rw-r--r--sql/sql_select.cc7
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)));