summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorbell@sanja.is.com.ua <>2002-12-26 01:28:59 +0200
committerbell@sanja.is.com.ua <>2002-12-26 01:28:59 +0200
commit1dd7cb52aedf01ee0aaddcdde2cbeec2c1a124a4 (patch)
tree6a73d0cc2b8728ab821e54448c158fa784365acb /sql
parent521ec3163e5de060d776e2e160fdab0d37ca7b6b (diff)
downloadmariadb-git-1dd7cb52aedf01ee0aaddcdde2cbeec2c1a124a4.tar.gz
support of subselect without FROM reducing (SCRUM)
fixed bug of calling setup_fields without correct lex->current_select pointer in mysql_derived more correct creation of reference in Item_field::fix_field
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc42
-rw-r--r--sql/item.h7
-rw-r--r--sql/item_cmpfunc.cc16
-rw-r--r--sql/item_cmpfunc.h12
-rw-r--r--sql/item_func.cc19
-rw-r--r--sql/item_func.h7
-rw-r--r--sql/item_row.cc17
-rw-r--r--sql/item_row.h2
-rw-r--r--sql/item_strfunc.h31
-rw-r--r--sql/item_subselect.cc48
-rw-r--r--sql/item_subselect.h1
-rw-r--r--sql/mysql_priv.h2
-rw-r--r--sql/sql_base.cc5
-rw-r--r--sql/sql_derived.cc9
14 files changed, 185 insertions, 33 deletions
diff --git a/sql/item.cc b/sql/item.cc
index 461f2ba9de5..1603e179e5e 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -546,8 +546,11 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
{
if (!field) // If field is not checked
{
- Field *tmp;
- if ((tmp= find_field_in_tables(thd, this, tables, 0)) == not_found_field)
+ TABLE_LIST *where= 0;
+ Field *tmp= (Field *)not_found_field;
+ if (outer_resolving ||
+ (tmp= find_field_in_tables(thd, this, tables, &where, 0)) ==
+ not_found_field)
{
/*
We can't find table field in table list of current select,
@@ -565,12 +568,12 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
SELECT_LEX *cursel=(SELECT_LEX *) thd->lex.current_select;
if (cursel->master_unit()->first_select()->linkage !=
DERIVED_TABLE_TYPE)
- for (SELECT_LEX *sl=cursel->outer_select();
+ for (SELECT_LEX *sl=(outer_resolving?cursel:cursel->outer_select());
sl;
sl= sl->outer_select())
{
if ((tmp= find_field_in_tables(thd, this,
- (last= sl)->get_table_list(),
+ (last= sl)->get_table_list(), &where,
0)) != not_found_field)
break;
if ((refer= find_item_in_list(this, sl->item_list,
@@ -588,7 +591,7 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
else if (tmp == not_found_field && refer == (Item **)not_found_item)
{
// call to return error code
- find_field_in_tables(thd, this, tables, 1);
+ find_field_in_tables(thd, this, tables, &where, 1);
return -1;
}
else if (refer != (Item **)not_found_item)
@@ -614,6 +617,17 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
found table as depended (of select where was found table)
*/
thd->lex.current_select->mark_as_dependent(last);
+ if (depended_from->having_fix_field)
+ {
+ Item_ref *rf;
+ *ref= rf= new Item_ref((where->db[0]?where->db:0),
+ (char *)where->alias,
+ (char *)field_name);
+ if (!rf)
+ return 1;
+ (rf)->outer_resolving= outer_resolving;
+ return rf->check_cols(1) || rf->fix_fields(thd, tables, ref);
+ }
}
}
else if (!tmp)
@@ -629,14 +643,6 @@ bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
table->used_fields++;
table->used_keys&=field->part_of_key;
}
- if (depended_from != 0 && depended_from->having_fix_field)
- {
- *ref= new Item_ref((char *)db_name, (char *)table_name,
- (char *)field_name);
- if (!*ref)
- return 1;
- return (*ref)->check_cols(1) || (*ref)->fix_fields(thd, tables, ref);
- }
fixed= 1;
return 0;
}
@@ -1007,13 +1013,17 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
if (!ref)
{
- SELECT_LEX *sl= thd->lex.current_select->outer_select();
+ TABLE_LIST *where= 0;
+ SELECT_LEX *sl= (outer_resolving?
+ thd->lex.current_select->select_lex():
+ thd->lex.current_select->outer_select());
/*
Finding only in current select will be performed for selects that have
not outer one and for derived tables (which not support using outer
fields for now)
*/
- if ((ref= find_item_in_list(this,
+ if (outer_resolving ||
+ (ref= find_item_in_list(this,
*(thd->lex.current_select->get_item_list()),
((sl &&
thd->lex.current_select->master_unit()->
@@ -1041,7 +1051,7 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
(Item **)not_found_item)
break;
if ((tmp= find_field_in_tables(thd, this,
- sl->get_table_list(),
+ sl->get_table_list(), &where,
0)) != not_found_field);
if (sl->master_unit()->first_select()->linkage ==
DERIVED_TABLE_TYPE)
diff --git a/sql/item.h b/sql/item.h
index 4e3c5f597ab..508c737e7b9 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -96,6 +96,7 @@ public:
CHARSET_INFO *thd_charset() const;
CHARSET_INFO *charset() const { return str_value.charset(); };
void set_charset(CHARSET_INFO *cs) { str_value.set_charset(cs); }
+ virtual void set_outer_resolving() {}
// Row emulation
virtual uint cols() { return 1; }
@@ -117,12 +118,14 @@ public:
const char *table_name;
const char *field_name;
st_select_lex *depended_from;
+ bool outer_resolving; /* used for items from reduced subselect */
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), depended_from(0)
+ :db_name(db_name_par), table_name(table_name_par),
+ field_name(field_name_par), depended_from(0), outer_resolving(0)
{ name = (char*) field_name_par; }
const char *full_name() const;
+ void set_outer_resolving() { outer_resolving= 1; }
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index df949a910bd..89ff5ef2822 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -946,6 +946,13 @@ Item_func_case::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 0;
}
+void Item_func_case::set_outer_resolving()
+{
+ first_expr->set_outer_resolving();
+ else_expr->set_outer_resolving();
+ Item_func::set_outer_resolving();
+}
+
bool Item_func_case::check_loop(uint id)
{
DBUG_ENTER("Item_func_case::check_loop");
@@ -1523,6 +1530,15 @@ bool Item_cond::check_loop(uint id)
DBUG_RETURN(0);
}
+void Item_cond::set_outer_resolving()
+{
+ Item_func::set_outer_resolving();
+ List_iterator<Item> li(list);
+ Item *item;
+ while ((item= li++))
+ item->set_outer_resolving();
+}
+
void Item_cond::split_sum_func(List<Item> &fields)
{
List_iterator<Item> li(list);
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index e3d8eb7746d..603d7123a6f 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -277,6 +277,11 @@ public:
const char *func_name() const { return "interval"; }
void update_used_tables();
bool check_loop(uint id);
+ void set_outer_resolving()
+ {
+ item->set_outer_resolving();
+ Item_func::set_outer_resolving();
+ }
};
@@ -359,6 +364,7 @@ public:
bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
Item *find_item(String *str);
bool check_loop(uint id);
+ void set_outer_resolving();
};
@@ -643,6 +649,11 @@ class Item_func_in :public Item_int_func
DBUG_RETURN(item->check_loop(id));
}
bool nulls_in_row();
+ void set_outer_resolving()
+ {
+ item->set_outer_resolving();
+ Item_int_func::set_outer_resolving();
+ }
};
/* Functions used by where clause */
@@ -784,6 +795,7 @@ public:
friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
bool check_loop(uint id);
void top_level_item() { abort_on_null=1; }
+ void set_outer_resolving();
};
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 19fd6b12c67..f0c956b873a 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -146,6 +146,16 @@ bool Item_func::check_loop(uint id)
DBUG_RETURN(0);
}
+void Item_func::set_outer_resolving()
+{
+ if (arg_count)
+ {
+ Item **arg,**arg_end;
+ for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
+ (*arg)->set_outer_resolving();
+ }
+}
+
void Item_func::split_sum_func(List<Item> &fields)
{
Item **arg,**arg_end;
@@ -2356,6 +2366,15 @@ bool Item_func_match::check_loop(uint id)
DBUG_RETURN(0);
}
+void Item_func_match::set_outer_resolving()
+{
+ Item_real_func::set_outer_resolving();
+ List_iterator<Item> li(fields);
+ Item *item;
+ while ((item= li++))
+ item->set_outer_resolving();
+}
+
bool Item_func_match::fix_index()
{
List_iterator_fast<Item> li(fields);
diff --git a/sql/item_func.h b/sql/item_func.h
index 36d6dcbe002..6ff2c7eef9d 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -133,6 +133,7 @@ public:
friend class udf_handler;
Field *tmp_table_field(TABLE *t_arg);
bool check_loop(uint id);
+ void set_outer_resolving();
};
@@ -632,6 +633,11 @@ public:
DBUG_RETURN(1);
DBUG_RETURN(item->check_loop(id));
}
+ void set_outer_resolving()
+ {
+ item->set_outer_resolving();
+ Item_int_func::set_outer_resolving();
+ }
};
@@ -1006,6 +1012,7 @@ public:
bool fix_index();
void init_search(bool no_order);
bool check_loop(uint id);
+ void set_outer_resolving();
};
diff --git a/sql/item_row.cc b/sql/item_row.cc
index 9d605e05242..b54653f4183 100644
--- a/sql/item_row.cc
+++ b/sql/item_row.cc
@@ -105,5 +105,20 @@ void Item_row::bring_value()
{
for (uint i= 0; i < arg_count; i++)
items[i]->bring_value();
- return;
+}
+
+void Item_row::set_outer_resolving()
+{
+ for (uint i= 0; i < arg_count; i++)
+ items[i]->set_outer_resolving();
+}
+
+bool Item_row::check_loop(uint id)
+{
+ if (Item::check_loop(id))
+ return 1;
+ for (uint i= 0; i < arg_count; i++)
+ if (items[i]->check_loop(id))
+ return 1;
+ return 0;
}
diff --git a/sql/item_row.h b/sql/item_row.h
index cf67567c3ed..f33e0cc9821 100644
--- a/sql/item_row.h
+++ b/sql/item_row.h
@@ -64,6 +64,8 @@ public:
bool const_item() const { return const_item_cache; };
enum Item_result result_type() const { return ROW_RESULT; }
void update_used_tables();
+ bool check_loop(uint id);
+ void set_outer_resolving();
uint cols() { return arg_count; }
Item* el(uint i) { return items[i]; }
diff --git a/sql/item_strfunc.h b/sql/item_strfunc.h
index c8706c2c933..12b003d7d82 100644
--- a/sql/item_strfunc.h
+++ b/sql/item_strfunc.h
@@ -108,14 +108,19 @@ public:
separator->fix_fields(thd, tlist, &separator) ||
Item_func::fix_fields(thd, tlist, ref));
}
- const char *func_name() const { return "concat_ws"; }
- bool check_loop(uint id)
- {
- DBUG_ENTER("Item_func_concat_ws::check_loop");
- if (Item_str_func::check_loop(id))
- DBUG_RETURN(1);
- DBUG_RETURN(separator->check_loop(id));
- }
+ const char *func_name() const { return "concat_ws"; }
+ bool check_loop(uint id)
+ {
+ DBUG_ENTER("Item_func_concat_ws::check_loop");
+ if (Item_str_func::check_loop(id))
+ DBUG_RETURN(1);
+ DBUG_RETURN(separator->check_loop(id));
+ }
+ void set_outer_resolving()
+ {
+ separator->set_outer_resolving();
+ Item_func::set_outer_resolving();
+ }
};
class Item_func_reverse :public Item_str_func
@@ -393,6 +398,11 @@ public:
DBUG_RETURN(1);
DBUG_RETURN(item->check_loop(id));
}
+ void set_outer_resolving()
+ {
+ item->set_outer_resolving();
+ Item_str_func::set_outer_resolving();
+ }
};
@@ -421,6 +431,11 @@ public:
DBUG_RETURN(1);
DBUG_RETURN(item->check_loop(id));
}
+ void set_outer_resolving()
+ {
+ item->set_outer_resolving();
+ Item_str_func::set_outer_resolving();
+ }
};
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 65c942a75ce..fe38c458495 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -146,6 +146,54 @@ void Item_singlerow_subselect::reset()
value->null_value= 1;
}
+void Item_singlerow_subselect::select_transformer(st_select_lex_unit *unit)
+{
+ SELECT_LEX *select_lex= unit->first_select();
+
+ if (!select_lex->next_select() && !select_lex->table_list.elements &&
+ select_lex->item_list.elements == 1)
+ {
+
+ have_to_be_excluded= 1;
+ THD *thd= current_thd;
+ if (thd->lex.describe)
+ {
+ char warn_buff[MYSQL_ERRMSG_SIZE];
+ sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_SELECT_REDUCED, warn_buff);
+ }
+ substitution= select_lex->item_list.head();
+ substitution->set_outer_resolving();
+ if (substitution->type() == FIELD_ITEM ||
+ substitution->type() == REF_ITEM)
+ name= substitution->name; // Save name for correct resolving
+
+ if (select_lex->where || select_lex->having)
+ {
+ Item *cond;
+ if (!select_lex->having)
+ cond= select_lex->where;
+ else if (!select_lex->where)
+ cond= select_lex->having;
+ else
+ if (!(cond= new Item_cond_and(select_lex->having, select_lex->where)))
+ {
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+ thd->fatal_error= 1;
+ return;
+ }
+ if (!(substitution= new Item_func_if(cond, substitution,
+ new Item_null())))
+ {
+ my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
+ thd->fatal_error= 1;
+ return;
+ }
+ }
+ }
+}
+
void Item_singlerow_subselect::store(uint i, Item *item)
{
row[i]->store(item);
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index 6063730d6a8..0d263f4aa39 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -106,6 +106,7 @@ public:
decimals= item->decimals;
}
void reset();
+ void select_transformer(st_select_lex_unit *unit);
void store(uint i, Item* item);
double val();
longlong val_int ();
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index cf0cefd76da..616a0573772 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -463,7 +463,7 @@ bool drop_locked_tables(THD *thd,const char *db, const char *table_name);
void abort_locked_tables(THD *thd,const char *db, const char *table_name);
extern const Field *not_found_field;
Field *find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
- bool report_error);
+ TABLE_LIST **where, bool report_error);
Field *find_field_in_table(THD *thd,TABLE *table,const char *name,uint length,
bool check_grant,bool allow_rowid);
#ifdef HAVE_OPENSSL
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index 87cc0d616a9..eb7fdf783d3 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -1654,6 +1654,7 @@ const Field *not_found_field= (Field*) 0x1;
thd - pointer to current thread structure
item - field item that should be found
tables - tables for scaning
+ where - table where field found will be returned via this parameter
report_error - if FALSE then do not report error if item not found and
return not_found_field;
@@ -1667,7 +1668,7 @@ const Field *not_found_field= (Field*) 0x1;
Field *
find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
- bool report_error)
+ TABLE_LIST **where, bool report_error)
{
Field *found=0;
const char *db=item->db_name;
@@ -1688,6 +1689,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
grant_option && !thd->master_access,1);
if (find)
{
+ (*where)= tables;
if (find == WRONG_GRANT)
return (Field*) 0;
if (db || !thd->where)
@@ -1742,6 +1744,7 @@ find_field_in_tables(THD *thd, Item_ident *item, TABLE_LIST *tables,
{
if (field == WRONG_GRANT)
return (Field*) 0;
+ (*where)= tables;
if (found)
{
if (!thd->where) // Returns first found
diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc
index f7d845e9e36..db516ae5f41 100644
--- a/sql/sql_derived.cc
+++ b/sql/sql_derived.cc
@@ -63,6 +63,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
TMP_TABLE_PARAM tmp_table_param;
bool is_union=sl->next_select() && sl->next_select()->linkage == UNION_TYPE;
DBUG_ENTER("mysql_derived");
+ SELECT_LEX_NODE *save_current_select= lex->current_select;
/*
@@ -111,6 +112,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
}
}
+ lex->current_select= sl;
if (setup_fields(thd,tables,item_list,0,0,1))
{
res=-1;
@@ -119,7 +121,8 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
bzero((char*) &tmp_table_param,sizeof(tmp_table_param));
tmp_table_param.field_count=item_list.elements;
if (!(table=create_tmp_table(thd, &tmp_table_param, item_list,
- (ORDER*) 0, is_union && !unit->union_option, 1,
+ (ORDER*) 0,
+ is_union && !unit->union_option, 1,
(sl->options | thd->options |
TMP_TABLE_ALL_COLUMNS),
HA_POS_ERROR)))
@@ -138,8 +141,6 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
if (unit->select_limit_cnt == HA_POS_ERROR)
sl->options&= ~OPTION_FOUND_ROWS;
- SELECT_LEX_NODE *save_current_select= lex->current_select;
- lex->current_select= sl;
if (is_union)
res=mysql_union(thd,lex,derived_result,unit);
else
@@ -149,7 +150,6 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
sl->having, (ORDER*) NULL,
sl->options | thd->options | SELECT_NO_UNLOCK,
derived_result, unit, sl, 0);
- lex->current_select= save_current_select;
if (!res)
{
@@ -184,6 +184,7 @@ int mysql_derived(THD *thd, LEX *lex, SELECT_LEX_UNIT *unit, TABLE_LIST *t)
if (res)
free_tmp_table(thd,table);
exit:
+ lex->current_select= save_current_select;
close_thread_tables(thd);
}
DBUG_RETURN(res);