Commit 41d93116 authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua

fixed cyclic reference bug

parent 9ef972fd
......@@ -259,4 +259,5 @@
#define ER_SUBSELECT_NO_1_ROW 1240
#define ER_UNKNOWN_STMT_HANDLER 1241
#define ER_CORRUPT_HELP_DB 1242
#define ER_ERROR_MESSAGES 243
#define ER_CYCLIC_REFERENCE 1243
#define ER_ERROR_MESSAGES 244
......@@ -8,6 +8,8 @@ SELECT (SELECT 1) UNION SELECT (SELECT 2);
SELECT (SELECT (SELECT 0 UNION SELECT 0));
(SELECT (SELECT 0 UNION SELECT 0))
0
SELECT (SELECT 1 FROM (SELECT 1) HAVING a=1) as a;
Cyclic reference on subqueries
drop table if exists t1,t2,t3,t4,t5,attend,clinic,inscrit;
create table t1 (a int);
create table t2 (a int, b int);
......@@ -46,7 +48,7 @@ a b
1 7
2 7
3 8
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
a b
1 7
......
select (select 2);
SELECT (SELECT 1) UNION SELECT (SELECT 2);
SELECT (SELECT (SELECT 0 UNION SELECT 0));
-- error 1243
SELECT (SELECT 1 FROM (SELECT 1) HAVING a=1) as a;
drop table if exists t1,t2,t3,t4,t5,attend,clinic,inscrit;
create table t1 (a int);
create table t2 (a int, b int);
......@@ -18,7 +20,7 @@ insert into t3 values (6),(7),(3);
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1);
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
union (select * from t4 order by a limit 2) limit 3;
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
explain select * from t2 where t2.b=(select a from t3 order by 1 desc limit 1)
union (select * from t4 where t4.b=(select max(t2.a)*4 from t2) order by a);
......
......@@ -42,6 +42,20 @@ Item::Item()
decimals=0; max_length=0;
next=current_thd->free_list; // Put in free list
current_thd->free_list=this;
loop_id= 0;
}
bool Item::check_loop(uint id)
{
DBUG_ENTER("Item::check_loop");
DBUG_PRINT("info", ("id %u, name %s", id, name));
if (loop_id == id)
{
DBUG_PRINT("info", ("id match"));
DBUG_RETURN(1);
}
loop_id= id;
DBUG_RETURN(0);
}
void Item::set_name(const char *str,uint length)
......@@ -862,6 +876,11 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
{
depended_from= last;
thd->lex.current_select->mark_as_dependent(last);
if (check_loop(thd->check_loops_counter++))
{
my_message(ER_CYCLIC_REFERENCE, ER(ER_CYCLIC_REFERENCE), MYF(0));
return 1;
}
}
}
else if (!ref)
......@@ -873,6 +892,14 @@ bool Item_ref::fix_fields(THD *thd,TABLE_LIST *tables, Item **reference)
return 0;
}
bool Item_ref::check_loop(uint id)
{
DBUG_ENTER("Item_ref::check_loop");
if (Item_ident::check_loop(id))
DBUG_RETURN(1);
DBUG_RETURN((*ref)->check_loop(id));
}
/*
** If item is a const function, calculate it and return a const item
** The original item is freed if not returned
......
......@@ -20,10 +20,11 @@
#endif
struct st_table_list;
void item_init(void); /* Init item functions */
void item_init(void); /* Init item functions */
class Item {
Item(const Item &); /* Prevent use of these */
uint loop_id; /* Used to find selfrefering loops */
Item(const Item &); /* Prevent use of these */
void operator=(Item &);
public:
static void *operator new(size_t size) {return (void*) sql_alloc((uint) size); }
......@@ -88,6 +89,8 @@ public:
virtual CHARSET_INFO *charset() const { return str_value.charset(); };
virtual bool binary() const { return str_value.charset()->state & MY_CS_BINSORT ? 1 : 0 ; }
virtual void set_charset(CHARSET_INFO *cs) { str_value.set_charset(cs); }
virtual bool check_loop(uint id);
};
......@@ -434,6 +437,7 @@ public:
void save_org_in_field(Field *field) { (*ref)->save_org_in_field(field); }
enum Item_result result_type () const { return (*ref)->result_type(); }
table_map used_tables() const { return (*ref)->used_tables(); }
bool check_loop(uint id);
};
......
......@@ -344,6 +344,14 @@ void Item_func_interval::update_used_tables()
const_item_cache&=item->const_item();
}
bool Item_func_interval::check_loop(uint id)
{
DBUG_ENTER("Item_func_interval::check_loop");
if (Item_func::check_loop(id))
DBUG_RETURN(1);
DBUG_RETURN(item->check_loop(id));
}
void Item_func_between::fix_length_and_dec()
{
max_length=1;
......@@ -776,6 +784,16 @@ Item_func_case::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 0;
}
bool Item_func_case::check_loop(uint id)
{
DBUG_ENTER("Item_func_case::check_loop");
if (Item_func::check_loop(id))
DBUG_RETURN(1);
DBUG_RETURN((first_expr && first_expr->check_loop(id)) ||
(else_expr && else_expr->check_loop(id)));
}
void Item_func_case::update_used_tables()
{
Item_func::update_used_tables();
......@@ -1137,6 +1155,20 @@ Item_cond::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 0;
}
bool Item_cond::check_loop(uint id)
{
DBUG_ENTER("Item_cond::check_loop");
if (Item_func::check_loop(id))
DBUG_RETURN(1);
List_iterator<Item> li(list);
Item *item;
while ((item= li++))
{
if (item->check_loop(id))
DBUG_RETURN(1);
}
DBUG_RETURN(0);
}
void Item_cond::split_sum_func(List<Item> &fields)
{
......
......@@ -186,6 +186,7 @@ public:
~Item_func_interval() { delete item; }
const char *func_name() const { return "interval"; }
void update_used_tables();
bool check_loop(uint id);
};
......@@ -262,6 +263,7 @@ public:
void print(String *str);
bool fix_fields(THD *thd, struct st_table_list *tlist, Item **ref);
Item *find_item(String *str);
bool check_loop(uint id);
};
......@@ -424,6 +426,13 @@ class Item_func_in :public Item_int_func
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
void update_used_tables();
bool check_loop(uint id)
{
DBUG_ENTER("Item_func_in::check_loop");
if (Item_func::check_loop(id))
DBUG_RETURN(1);
DBUG_RETURN(item->check_loop(id));
}
};
......@@ -563,6 +572,7 @@ public:
void print(String *str);
void split_sum_func(List<Item> &fields);
friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
bool check_loop(uint id);
};
......
......@@ -126,6 +126,22 @@ Item_func::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return 0;
}
bool Item_func::check_loop(uint id)
{
DBUG_ENTER("Item_func::check_loop");
if (Item_result_field::check_loop(id))
DBUG_RETURN(1);
if (arg_count)
{
Item **arg,**arg_end;
for (arg= args, arg_end= args+arg_count; arg != arg_end; arg++)
{
if ((*arg)->check_loop(id))
DBUG_RETURN(1);
}
}
DBUG_RETURN(0);
}
void Item_func::split_sum_func(List<Item> &fields)
{
......@@ -2264,6 +2280,19 @@ bool Item_func_match::fix_fields(THD *thd, TABLE_LIST *tlist, Item **ref)
return 0;
}
bool Item_func_match::check_loop(uint id)
{
DBUG_ENTER("Item_func_match::check_loop");
if (Item_real_func::check_loop(id))
DBUG_RETURN(1);
List_iterator<Item> li(fields);
Item *item;
while ((item= li++))
if (item->check_loop(id))
DBUG_RETURN(1);
DBUG_RETURN(0);
}
bool Item_func_match::fix_index()
{
......
......@@ -128,6 +128,7 @@ public:
bool is_null() { (void) val_int(); return null_value; }
friend class udf_handler;
Field *tmp_table_field(TABLE *t_arg);
bool check_loop(uint id);
};
......@@ -606,6 +607,13 @@ public:
const_item_cache&= item->const_item();
with_sum_func= with_sum_func || item->with_sum_func;
}
bool check_loop(uint id)
{
DBUG_ENTER("Item_func_field::check_loop");
if (Item_int_func::check_loop(id))
DBUG_RETURN(1);
DBUG_RETURN(item->check_loop(id));
}
};
......@@ -971,6 +979,7 @@ public:
bool fix_index();
void init_search(bool no_order);
bool check_loop(uint id);
};
......
......@@ -105,6 +105,13 @@ public:
|| 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));
}
};
class Item_func_reverse :public Item_str_func
......@@ -361,6 +368,13 @@ public:
void fix_length_and_dec();
void update_used_tables();
const char *func_name() const { return "elt"; }
bool check_loop(uint id)
{
DBUG_ENTER("Item_func_elt::check_loop");
if (Item_str_func::check_loop(id))
DBUG_RETURN(1);
DBUG_RETURN(item->check_loop(id));
}
};
......@@ -381,6 +395,13 @@ public:
void fix_length_and_dec();
void update_used_tables();
const char *func_name() const { return "make_set"; }
bool check_loop(uint id)
{
DBUG_ENTER("Item_func_make_set::check_loop");
if (Item_str_func::check_loop(id))
DBUG_RETURN(1);
DBUG_RETURN(item->check_loop(id));
}
};
......
......@@ -95,6 +95,15 @@ bool Item_subselect::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
return res;
}
bool Item_subselect::check_loop(uint id)
{
DBUG_ENTER("Item_subselect::check_loop");
if (Item_result_field::check_loop(id))
DBUG_RETURN(1);
DBUG_RETURN(engine->check_loop(id));
}
void Item_subselect::fix_length_and_dec()
{
engine->fix_length_and_dec();
......@@ -228,6 +237,7 @@ subselect_single_select_engine::subselect_single_select_engine(THD *thd,
thd->fatal_error= 1;
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
}
unit->item= item;
this->select_lex= select_lex;
}
......@@ -353,3 +363,18 @@ bool subselect_union_engine::depended()
{
return unit->dependent;
}
bool subselect_single_select_engine::check_loop(uint id)
{
DBUG_ENTER("subselect_single_select_engine::check_loop");
DBUG_RETURN(join->check_loop(id));
}
bool subselect_union_engine::check_loop(uint id)
{
DBUG_ENTER("subselect_union_engine::check_loop");
for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
if (sl->join && sl->join->check_loop(id))
DBUG_RETURN(1);
DBUG_RETURN(0);
}
......@@ -70,6 +70,7 @@ public:
bool fix_fields(THD *thd, TABLE_LIST *tables, Item **ref);
virtual void fix_length_and_dec();
table_map used_tables() const;
bool check_loop(uint id);
friend class select_subselect;
};
......@@ -176,6 +177,7 @@ public:
virtual uint cols()= 0; /* return number of columnss in select */
virtual bool depended()= 0; /* depended from outer select */
enum Item_result type() { return res_type; }
virtual bool check_loop(uint id)= 0;
};
class subselect_single_select_engine: public subselect_engine
......@@ -189,11 +191,12 @@ public:
subselect_single_select_engine(THD *thd, st_select_lex *select,
select_subselect *result,
Item_subselect *item);
virtual int prepare();
virtual void fix_length_and_dec();
virtual int exec();
virtual uint cols();
virtual bool depended();
int prepare();
void fix_length_and_dec();
int exec();
uint cols();
bool depended();
bool check_loop(uint id);
};
class subselect_union_engine: public subselect_engine
......@@ -204,9 +207,10 @@ public:
st_select_lex_unit *u,
select_subselect *result,
Item_subselect *item);
virtual int prepare();
virtual void fix_length_and_dec();
virtual int exec();
virtual uint cols();
virtual bool depended();
int prepare();
void fix_length_and_dec();
int exec();
uint cols();
bool depended();
bool check_loop(uint id);
};
......@@ -252,4 +252,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -246,4 +246,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -254,4 +254,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -243,4 +243,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -248,4 +248,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -243,4 +243,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -246,4 +246,5 @@
"Subselect return more than 1 field",
"Subselect return more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -243,4 +243,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -245,4 +245,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -243,4 +243,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -245,4 +245,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -243,4 +243,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -245,4 +245,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -245,4 +245,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -247,4 +247,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -243,4 +243,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -247,4 +247,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -246,4 +246,5 @@
" ",
" ",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
" ",
......@@ -239,4 +239,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -251,4 +251,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -244,4 +244,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -243,4 +243,5 @@
"Subselect returns more than 1 field",
"Subselect returns more than 1 record",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"Cyclic reference on subqueries",
......@@ -248,4 +248,5 @@
"i i i 1 ",
"i i i 1 ",
"Unknown prepared statement handler (%ld) given to %s",
"Help database is corrupt or does not exist",
\ No newline at end of file
"Help database is corrupt or does not exist",
"i i",
......@@ -494,6 +494,7 @@ public:
uint32 query_length;
uint32 db_length;
uint select_number; //number of select (used for EXPLAIN)
uint check_loops_counter; //last id used to check loops
/* variables.transaction_isolation is reset to this after each commit */
enum_tx_isolation session_tx_isolation;
char scramble[9];
......
......@@ -2867,7 +2867,8 @@ mysql_init_query(THD *thd)
lex->select_lex.prev= &lex->unit.slave;
lex->olap=lex->describe=0;
lex->derived_tables= false;
thd->select_number= lex->select_lex.select_number= 1;
thd->check_loops_counter= thd->select_number=
lex->select_lex.select_number= 1;
thd->free_list= 0;
thd->total_warn_count=0; // Warnings for this query
thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0;
......
......@@ -1035,6 +1035,24 @@ JOIN::cleanup(THD *thd)
DBUG_RETURN(error);
}
bool JOIN::check_loop(uint id)
{
DBUG_ENTER("JOIN::check_loop");
Item *item;
List_iterator<Item> it(all_fields);
DBUG_PRINT("info", ("all_fields:"));
while ((item= it++))
if (item->check_loop(id))
DBUG_RETURN(1);
DBUG_PRINT("info", ("where:"));
if (select_lex->where && select_lex->where->check_loop(id))
DBUG_RETURN(1);
DBUG_PRINT("info", ("having:"));
if (select_lex->having && select_lex->having->check_loop(id))
DBUG_RETURN(1);
DBUG_RETURN(0);
}
int
mysql_select(THD *thd, TABLE_LIST *tables, List<Item> &fields, COND *conds,
ORDER *order, ORDER *group,Item *having, ORDER *proc_param,
......
......@@ -244,7 +244,8 @@ class JOIN :public Sql_alloc
int global_optimize();
int reinit();
void exec();
int cleanup(THD *thd);
int cleanup(THD *thd);
bool check_loop(uint id);
};
......
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