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

EXISTS type of subselect

more correct parameters in result creation script
parent 9e77c6d8
...@@ -32,7 +32,7 @@ result_file=$RESULT_DIR/$test_name.result ...@@ -32,7 +32,7 @@ result_file=$RESULT_DIR/$test_name.result
touch $result_file touch $result_file
echo "Running the test case against empty file, will fail, but don't worry" echo "Running the test case against empty file, will fail, but don't worry"
./mysql-test-run --do-test=$test_name ./mysql-test-run --local $test_name
reject_file=$result_file.reject reject_file=$result_file.reject
......
...@@ -67,4 +67,11 @@ b (select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) ...@@ -67,4 +67,11 @@ b (select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2)
8 7.5000 8 7.5000
8 6.0000 8 6.0000
9 5.5000 9 5.5000
select * from t3 where exists (select * from t2 where t2.b=t3.a);
a
7
select * from t3 where not exists (select * from t2 where t2.b=t3.a);
a
6
3
drop table t1,t2,t3,t4; drop table t1,t2,t3,t4;
...@@ -26,4 +26,6 @@ select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from ...@@ -26,4 +26,6 @@ select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from
select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a > t1.a) order by 1 desc limit 1); select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a > t1.a) order by 1 desc limit 1);
select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a < t1.a) order by 1 desc limit 1); select * from t1 where t1.a=(select t2.a from t2 where t2.b=(select max(a) from t3 where t3.a < t1.a) order by 1 desc limit 1);
select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4; select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2) from t4;
select * from t3 where exists (select * from t2 where t2.b=t3.a);
select * from t3 where not exists (select * from t2 where t2.b=t3.a);
drop table t1,t2,t3,t4; drop table t1,t2,t3,t4;
...@@ -35,12 +35,13 @@ SUBSELECT TODO: ...@@ -35,12 +35,13 @@ SUBSELECT TODO:
#include "mysql_priv.h" #include "mysql_priv.h"
#include "sql_select.h" #include "sql_select.h"
Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex): Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex,
select_subselect *result):
assigned(0), executed(0), optimized(0), error(0) assigned(0), executed(0), optimized(0), error(0)
{ {
DBUG_ENTER("Item_subselect::Item_subselect"); DBUG_ENTER("Item_subselect::Item_subselect");
DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex)); DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex));
result= new select_subselect(this); this->result= result;
SELECT_LEX_UNIT *unit= select_lex->master_unit(); SELECT_LEX_UNIT *unit= select_lex->master_unit();
unit->offset_limit_cnt= unit->global_parameters->offset_limit; unit->offset_limit_cnt= unit->global_parameters->offset_limit;
unit->select_limit_cnt= unit->global_parameters->select_limit+ unit->select_limit_cnt= unit->global_parameters->select_limit+
...@@ -51,41 +52,15 @@ Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex): ...@@ -51,41 +52,15 @@ Item_subselect::Item_subselect(THD *thd, st_select_lex *select_lex):
select_lex->options&= ~OPTION_FOUND_ROWS; select_lex->options&= ~OPTION_FOUND_ROWS;
join= new JOIN(thd, select_lex->item_list, select_lex->options, result); join= new JOIN(thd, select_lex->item_list, select_lex->options, result);
this->select_lex= select_lex; this->select_lex= select_lex;
maybe_null= 1; assign_null();
/* /*
item value is NULL if select_subselect not changed this value item value is NULL if select_subselect not changed this value
(i.e. some rows will be found returned) (i.e. some rows will be found returned)
*/ */
assign_null(); null_value= 1;
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
Item::Type Item_subselect::type() const
{
return SUBSELECT_ITEM;
}
double Item_subselect::val ()
{
if (exec())
return 0;
return real_value;
}
longlong Item_subselect::val_int ()
{
if (exec())
return 0;
return int_value;
}
String *Item_subselect::val_str (String *str)
{
if (exec() || null_value)
return 0;
return &str_value;
}
void Item_subselect::make_field (Send_field *tmp_field) void Item_subselect::make_field (Send_field *tmp_field)
{ {
if (null_value) if (null_value)
...@@ -110,7 +85,7 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables) ...@@ -110,7 +85,7 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables)
return 1; return 1;
} }
// Is it one field subselect? // Is it one field subselect?
if (select_lex->item_list.elements != 1) if (select_lex->item_list.elements > max_columns)
{ {
my_printf_error(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0)); my_printf_error(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0));
return 1; return 1;
...@@ -131,13 +106,14 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables) ...@@ -131,13 +106,14 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables)
int Item_subselect::exec() int Item_subselect::exec()
{ {
DBUG_ENTER("Item_subselect::exec");
if (!optimized) if (!optimized)
{ {
optimized=1; optimized=1;
if (join->optimize()) if (join->optimize())
{ {
executed= 1; executed= 1;
return (join->error?join->error:1); DBUG_RETURN(join->error?join->error:1);
} }
} }
if (join->select_lex->depended && executed) if (join->select_lex->depended && executed)
...@@ -145,7 +121,7 @@ int Item_subselect::exec() ...@@ -145,7 +121,7 @@ int Item_subselect::exec()
if (join->reinit()) if (join->reinit())
{ {
error= 1; error= 1;
return 1; DBUG_RETURN(1);
} }
assign_null(); assign_null();
executed= assigned= 0; executed= assigned= 0;
...@@ -157,7 +133,80 @@ int Item_subselect::exec() ...@@ -157,7 +133,80 @@ int Item_subselect::exec()
join->exec(); join->exec();
join->thd->lex.select= save_select; join->thd->lex.select= save_select;
executed= 1; executed= 1;
return join->error; DBUG_RETURN(join->error);
} }
DBUG_RETURN(0);
}
inline table_map Item_subselect::used_tables() const
{
return (table_map) select_lex->depended ? 1L : 0L;
}
Item_singleval_subselect::Item_singleval_subselect(THD *thd,
st_select_lex *select_lex):
Item_subselect(thd, select_lex, new select_singleval_subselect(this))
{
max_columns= 1;
maybe_null= 1;
}
Item::Type Item_subselect::type() const
{
return SUBSELECT_ITEM;
}
double Item_singleval_subselect::val ()
{
if (exec())
return 0; return 0;
return real_value;
} }
longlong Item_singleval_subselect::val_int ()
{
if (exec())
return 0;
return int_value;
}
String *Item_singleval_subselect::val_str (String *str)
{
if (exec() || null_value)
return 0;
return &str_value;
}
Item_exists_subselect::Item_exists_subselect(THD *thd,
st_select_lex *select_lex):
Item_subselect(thd, select_lex, new select_singleval_subselect(this))
{
max_columns= UINT_MAX;
null_value= 0; //can't be NULL
maybe_null= 0; //can't be NULL
value= 0;
select_lex->select_limit= 1; // we need only 1 row to determinate existence
}
double Item_exists_subselect::val ()
{
if (exec())
return 0;
return (double) value;
}
longlong Item_exists_subselect::val_int ()
{
if (exec())
return 0;
return value;
}
String *Item_exists_subselect::val_str(String *str)
{
if (exec())
return 0;
str->set(value);
return str;
}
...@@ -24,42 +24,34 @@ struct st_select_lex; ...@@ -24,42 +24,34 @@ struct st_select_lex;
class JOIN; class JOIN;
class select_subselect; class select_subselect;
/* simple (not depended of covered select ) subselect */ /* base class for subselects */
class Item_subselect :public Item class Item_subselect :public Item
{ {
protected: protected:
longlong int_value; uint max_columns;
double real_value;
my_bool assigned; /* value already assigned to subselect */ my_bool assigned; /* value already assigned to subselect */
my_bool executed; /* simple subselect is executed */ my_bool executed; /* simple subselect is executed */
my_bool optimized; /* simple subselect is optimized */ my_bool optimized; /* simple subselect is optimized */
my_bool error; /* error in query */ my_bool error; /* error in query */
enum Item_result res_type;
int exec(); int exec();
void assign_null() virtual void assign_null()
{ {
null_value= 1; null_value= 1;
int_value= 0;
real_value= 0;
max_length= 4;
res_type= STRING_RESULT;
} }
public: public:
st_select_lex *select_lex; st_select_lex *select_lex;
JOIN *join; JOIN *join;
select_subselect *result; select_subselect *result;
Item_subselect(THD *thd, st_select_lex *select_lex); Item_subselect(THD *thd, st_select_lex *select_lex,
select_subselect* result);
Item_subselect(Item_subselect *item) Item_subselect(Item_subselect *item)
{ {
null_value= item->null_value; null_value= item->null_value;
int_value= item->int_value;
real_value= item->real_value;
max_length= item->max_length;
decimals= item->decimals; decimals= item->decimals;
res_type= item->res_type; max_columns= item->max_columns;
assigned= item->assigned; assigned= item->assigned;
executed= item->executed; executed= item->executed;
select_lex= item->select_lex; select_lex= item->select_lex;
...@@ -69,16 +61,75 @@ public: ...@@ -69,16 +61,75 @@ public:
error= item->error; error= item->error;
} }
enum Type type() const; enum Type type() const;
double val ();
longlong val_int ();
String *val_str (String *);
bool is_null() { return null_value; } bool is_null() { return null_value; }
void make_field (Send_field *); void make_field (Send_field *);
bool fix_fields(THD *thd, TABLE_LIST *tables); bool fix_fields(THD *thd, TABLE_LIST *tables);
Item *new_item() { return new Item_subselect(this); } table_map used_tables() const;
enum Item_result result_type() const { return res_type; }
friend class select_subselect; friend class select_subselect;
}; };
/* single value subselect */
class Item_singleval_subselect :public Item_subselect
{
protected:
longlong int_value;
double real_value;
enum Item_result res_type;
virtual void assign_null()
{
null_value= 1;
int_value= 0;
real_value= 0;
max_length= 4;
res_type= STRING_RESULT;
}
public:
Item_singleval_subselect(THD *thd, st_select_lex *select_lex);
Item_singleval_subselect(Item_singleval_subselect *item):
Item_subselect(item)
{
int_value= item->int_value;
real_value= item->real_value;
max_length= item->max_length;
decimals= item->decimals;
res_type= item->res_type;
}
double val ();
longlong val_int ();
String *val_str (String *);
Item *new_item() { return new Item_singleval_subselect(this); }
enum Item_result result_type() const { return res_type; }
friend class select_singleval_subselect;
};
/* exists subselect */
class Item_exists_subselect :public Item_subselect
{
protected:
longlong value;
virtual void assign_null()
{
value= 0;
}
public:
Item_exists_subselect(THD *thd, st_select_lex *select_lex);
Item_exists_subselect(Item_exists_subselect *item):
Item_subselect(item)
{
value= item->value;
}
Item *new_item() { return new Item_exists_subselect(this); }
enum Item_result result_type() const { return INT_RESULT;}
longlong val_int();
double val();
String *val_str(String*);
friend class select_exists_subselect;
};
...@@ -763,7 +763,6 @@ void select_dump::send_error(uint errcode,const char *err) ...@@ -763,7 +763,6 @@ void select_dump::send_error(uint errcode,const char *err)
file= -1; file= -1;
} }
bool select_dump::send_eof() bool select_dump::send_eof()
{ {
int error=test(end_io_cache(&cache)); int error=test(end_io_cache(&cache));
...@@ -782,10 +781,11 @@ select_subselect::select_subselect(Item_subselect *item) ...@@ -782,10 +781,11 @@ select_subselect::select_subselect(Item_subselect *item)
this->item=item; this->item=item;
} }
bool select_subselect::send_data(List<Item> &items) bool select_singleval_subselect::send_data(List<Item> &items)
{ {
DBUG_ENTER("select_subselect::send_data"); DBUG_ENTER("select_singleval_subselect::send_data");
if (item->assigned){ Item_singleval_subselect *it= (Item_singleval_subselect *)item;
if (it->assigned){
my_printf_error(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0)); my_printf_error(ER_SUBSELECT_NO_1_ROW, ER(ER_SUBSELECT_NO_1_ROW), MYF(0));
DBUG_RETURN(1); DBUG_RETURN(1);
} }
...@@ -800,18 +800,33 @@ bool select_subselect::send_data(List<Item> &items) ...@@ -800,18 +800,33 @@ bool select_subselect::send_data(List<Item> &items)
Following val() call have to be first, because function AVG() & STD() Following val() call have to be first, because function AVG() & STD()
calculate value on it & determinate "is it NULL?". calculate value on it & determinate "is it NULL?".
*/ */
item->real_value= val_item->val(); it->real_value= val_item->val();
if ((item->null_value= val_item->is_null())) if ((it->null_value= val_item->is_null()))
{ {
item->assign_null(); it->assign_null();
} else { } else {
item->max_length= val_item->max_length; it->max_length= val_item->max_length;
item->decimals= val_item->decimals; it->decimals= val_item->decimals;
item->binary= val_item->binary; it->binary= val_item->binary;
val_item->val_str(&item->str_value); val_item->val_str(&it->str_value);
item->int_value= val_item->val_int(); it->int_value= val_item->val_int();
item->res_type= val_item->result_type(); it->res_type= val_item->result_type();
} }
item->assigned= 1; it->assigned= 1;
DBUG_RETURN(0); DBUG_RETURN(0);
} }
bool select_exists_subselect::send_data(List<Item> &items)
{
DBUG_ENTER("select_exists_subselect::send_data");
Item_exists_subselect *it= (Item_exists_subselect *)item;
if (unit->offset_limit_cnt)
{ // Using limit offset,count
unit->offset_limit_cnt--;
DBUG_RETURN(0);
}
it->value= 1;
it->assigned= 1;
DBUG_RETURN(0);
}
...@@ -712,19 +712,36 @@ class select_union :public select_result { ...@@ -712,19 +712,36 @@ class select_union :public select_result {
bool flush(); bool flush();
}; };
/* Single value subselect interface class */ /* Base subselect interface class */
class select_subselect :public select_result class select_subselect :public select_result
{ {
protected:
Item_subselect *item; Item_subselect *item;
public: public:
select_subselect(Item_subselect *item); select_subselect(Item_subselect *item);
bool send_fields(List<Item> &list, uint flag) { return 0; }; bool send_fields(List<Item> &list, uint flag) { return 0; };
bool send_data(List<Item> &items); bool send_data(List<Item> &items)=0;
bool send_eof() { return 0; }; bool send_eof() { return 0; };
friend class Ttem_subselect; friend class Ttem_subselect;
}; };
/* Single value subselect interface class */
class select_singleval_subselect :public select_subselect
{
public:
select_singleval_subselect(Item_subselect *item):select_subselect(item){}
bool send_data(List<Item> &items);
};
/* EXISTS subselect interface class */
class select_exists_subselect :public select_subselect
{
public:
select_exists_subselect(Item_subselect *item):select_subselect(item){}
bool send_data(List<Item> &items);
};
/* Structs used when sorting */ /* Structs used when sorting */
typedef struct st_sort_field { typedef struct st_sort_field {
......
...@@ -548,7 +548,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -548,7 +548,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
literal text_literal insert_ident order_ident literal text_literal insert_ident order_ident
simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr simple_ident select_item2 expr opt_expr opt_else sum_expr in_sum_expr
table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr table_wild opt_pad no_in_expr expr_expr simple_expr no_and_expr
using_list subselect subselect_init using_list singleval_subselect singleval_subselect_init
exists_subselect exists_subselect_init
%type <item_list> %type <item_list>
expr_list udf_expr_list when_list ident_list ident_list_arg expr_list udf_expr_list when_list ident_list ident_list_arg
...@@ -1738,7 +1739,8 @@ simple_expr: ...@@ -1738,7 +1739,8 @@ simple_expr:
| NOT expr %prec NEG { $$= new Item_func_not($2); } | NOT expr %prec NEG { $$= new Item_func_not($2); }
| '!' expr %prec NEG { $$= new Item_func_not($2); } | '!' expr %prec NEG { $$= new Item_func_not($2); }
| '(' expr ')' { $$= $2; } | '(' expr ')' { $$= $2; }
| subselect { $$= $1; } | EXISTS exists_subselect { $$= $2; }
| singleval_subselect { $$= $1; }
| '{' ident expr '}' { $$= $3; } | '{' ident expr '}' { $$= $3; }
| MATCH ident_list_arg AGAINST '(' expr ')' | MATCH ident_list_arg AGAINST '(' expr ')'
{ Select->ftfunc_list.push_back((Item_func_match *) { Select->ftfunc_list.push_back((Item_func_match *)
...@@ -3918,17 +3920,30 @@ union_option: ...@@ -3918,17 +3920,30 @@ union_option:
/* empty */ {} /* empty */ {}
| ALL {Lex->union_option=1;}; | ALL {Lex->union_option=1;};
subselect: singleval_subselect:
subselect_start subselect_init subselect_start singleval_subselect_init
subselect_end subselect_end
{ {
$$= $2; $$= $2;
}; };
subselect_init: singleval_subselect_init:
select_init select_init
{ {
$$= new Item_subselect(current_thd, Lex->select); $$= new Item_singleval_subselect(current_thd, Lex->select);
};
exists_subselect:
subselect_start exists_subselect_init
subselect_end
{
$$= $2;
};
exists_subselect_init:
select_init
{
$$= new Item_exists_subselect(current_thd, Lex->select);
}; };
subselect_start: subselect_start:
......
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