mirror of
https://github.com/MariaDB/server.git
synced 2025-01-16 20:12:31 +01:00
EXISTS type of subselect
more correct parameters in result creation script
This commit is contained in:
parent
9e77c6d8e7
commit
f974c735cf
8 changed files with 235 additions and 79 deletions
|
@ -32,7 +32,7 @@ result_file=$RESULT_DIR/$test_name.result
|
|||
|
||||
touch $result_file
|
||||
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
|
||||
|
||||
|
|
|
@ -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 6.0000
|
||||
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;
|
||||
|
|
|
@ -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 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;
|
||||
|
|
|
@ -35,12 +35,13 @@ SUBSELECT TODO:
|
|||
#include "mysql_priv.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)
|
||||
{
|
||||
DBUG_ENTER("Item_subselect::Item_subselect");
|
||||
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();
|
||||
unit->offset_limit_cnt= unit->global_parameters->offset_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):
|
|||
select_lex->options&= ~OPTION_FOUND_ROWS;
|
||||
join= new JOIN(thd, select_lex->item_list, select_lex->options, result);
|
||||
this->select_lex= select_lex;
|
||||
maybe_null= 1;
|
||||
assign_null();
|
||||
/*
|
||||
item value is NULL if select_subselect not changed this value
|
||||
(i.e. some rows will be found returned)
|
||||
*/
|
||||
assign_null();
|
||||
null_value= 1;
|
||||
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)
|
||||
{
|
||||
if (null_value)
|
||||
|
@ -108,9 +83,9 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables)
|
|||
//TODO: subselects in having do not suported now
|
||||
my_printf_error(ER_SYNTAX_ERROR, ER(ER_SYNTAX_ERROR), MYF(0));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
// 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));
|
||||
return 1;
|
||||
|
@ -131,13 +106,14 @@ bool Item_subselect::fix_fields(THD *thd,TABLE_LIST *tables)
|
|||
|
||||
int Item_subselect::exec()
|
||||
{
|
||||
DBUG_ENTER("Item_subselect::exec");
|
||||
if (!optimized)
|
||||
{
|
||||
optimized=1;
|
||||
if (join->optimize())
|
||||
{
|
||||
executed= 1;
|
||||
return (join->error?join->error:1);
|
||||
DBUG_RETURN(join->error?join->error:1);
|
||||
}
|
||||
}
|
||||
if (join->select_lex->depended && executed)
|
||||
|
@ -145,7 +121,7 @@ int Item_subselect::exec()
|
|||
if (join->reinit())
|
||||
{
|
||||
error= 1;
|
||||
return 1;
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
assign_null();
|
||||
executed= assigned= 0;
|
||||
|
@ -157,7 +133,80 @@ int Item_subselect::exec()
|
|||
join->exec();
|
||||
join->thd->lex.select= save_select;
|
||||
executed= 1;
|
||||
return join->error;
|
||||
DBUG_RETURN(join->error);
|
||||
}
|
||||
return 0;
|
||||
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 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;
|
|||
class JOIN;
|
||||
class select_subselect;
|
||||
|
||||
/* simple (not depended of covered select ) subselect */
|
||||
/* base class for subselects */
|
||||
|
||||
class Item_subselect :public Item
|
||||
{
|
||||
protected:
|
||||
longlong int_value;
|
||||
double real_value;
|
||||
uint max_columns;
|
||||
my_bool assigned; /* value already assigned to subselect */
|
||||
my_bool executed; /* simple subselect is executed */
|
||||
my_bool optimized; /* simple subselect is optimized */
|
||||
my_bool error; /* error in query */
|
||||
enum Item_result res_type;
|
||||
|
||||
int exec();
|
||||
void assign_null()
|
||||
virtual void assign_null()
|
||||
{
|
||||
null_value= 1;
|
||||
int_value= 0;
|
||||
real_value= 0;
|
||||
max_length= 4;
|
||||
res_type= STRING_RESULT;
|
||||
}
|
||||
public:
|
||||
st_select_lex *select_lex;
|
||||
JOIN *join;
|
||||
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)
|
||||
{
|
||||
null_value= item->null_value;
|
||||
int_value= item->int_value;
|
||||
real_value= item->real_value;
|
||||
max_length= item->max_length;
|
||||
decimals= item->decimals;
|
||||
res_type= item->res_type;
|
||||
max_columns= item->max_columns;
|
||||
assigned= item->assigned;
|
||||
executed= item->executed;
|
||||
select_lex= item->select_lex;
|
||||
|
@ -69,16 +61,75 @@ public:
|
|||
error= item->error;
|
||||
}
|
||||
enum Type type() const;
|
||||
double val ();
|
||||
longlong val_int ();
|
||||
String *val_str (String *);
|
||||
bool is_null() { return null_value; }
|
||||
void make_field (Send_field *);
|
||||
bool fix_fields(THD *thd, TABLE_LIST *tables);
|
||||
Item *new_item() { return new Item_subselect(this); }
|
||||
enum Item_result result_type() const { return res_type; }
|
||||
table_map used_tables() const;
|
||||
|
||||
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)
|
|||
file= -1;
|
||||
}
|
||||
|
||||
|
||||
bool select_dump::send_eof()
|
||||
{
|
||||
int error=test(end_io_cache(&cache));
|
||||
|
@ -782,10 +781,11 @@ select_subselect::select_subselect(Item_subselect *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");
|
||||
if (item->assigned){
|
||||
DBUG_ENTER("select_singleval_subselect::send_data");
|
||||
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));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
@ -800,18 +800,33 @@ bool select_subselect::send_data(List<Item> &items)
|
|||
Following val() call have to be first, because function AVG() & STD()
|
||||
calculate value on it & determinate "is it NULL?".
|
||||
*/
|
||||
item->real_value= val_item->val();
|
||||
if ((item->null_value= val_item->is_null()))
|
||||
it->real_value= val_item->val();
|
||||
if ((it->null_value= val_item->is_null()))
|
||||
{
|
||||
item->assign_null();
|
||||
it->assign_null();
|
||||
} else {
|
||||
item->max_length= val_item->max_length;
|
||||
item->decimals= val_item->decimals;
|
||||
item->binary= val_item->binary;
|
||||
val_item->val_str(&item->str_value);
|
||||
item->int_value= val_item->val_int();
|
||||
item->res_type= val_item->result_type();
|
||||
it->max_length= val_item->max_length;
|
||||
it->decimals= val_item->decimals;
|
||||
it->binary= val_item->binary;
|
||||
val_item->val_str(&it->str_value);
|
||||
it->int_value= val_item->val_int();
|
||||
it->res_type= val_item->result_type();
|
||||
}
|
||||
item->assigned= 1;
|
||||
it->assigned= 1;
|
||||
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 {
|
|||
bool flush();
|
||||
};
|
||||
|
||||
/* Single value subselect interface class */
|
||||
/* Base subselect interface class */
|
||||
class select_subselect :public select_result
|
||||
{
|
||||
protected:
|
||||
Item_subselect *item;
|
||||
public:
|
||||
select_subselect(Item_subselect *item);
|
||||
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; };
|
||||
|
||||
|
||||
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 */
|
||||
|
||||
typedef struct st_sort_field {
|
||||
|
|
|
@ -548,7 +548,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
|||
literal text_literal insert_ident order_ident
|
||||
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
|
||||
using_list subselect subselect_init
|
||||
using_list singleval_subselect singleval_subselect_init
|
||||
exists_subselect exists_subselect_init
|
||||
|
||||
%type <item_list>
|
||||
expr_list udf_expr_list when_list ident_list ident_list_arg
|
||||
|
@ -1738,7 +1739,8 @@ simple_expr:
|
|||
| NOT expr %prec NEG { $$= new Item_func_not($2); }
|
||||
| '!' expr %prec NEG { $$= new Item_func_not($2); }
|
||||
| '(' expr ')' { $$= $2; }
|
||||
| subselect { $$= $1; }
|
||||
| EXISTS exists_subselect { $$= $2; }
|
||||
| singleval_subselect { $$= $1; }
|
||||
| '{' ident expr '}' { $$= $3; }
|
||||
| MATCH ident_list_arg AGAINST '(' expr ')'
|
||||
{ Select->ftfunc_list.push_back((Item_func_match *)
|
||||
|
@ -3918,17 +3920,30 @@ union_option:
|
|||
/* empty */ {}
|
||||
| ALL {Lex->union_option=1;};
|
||||
|
||||
subselect:
|
||||
subselect_start subselect_init
|
||||
singleval_subselect:
|
||||
subselect_start singleval_subselect_init
|
||||
subselect_end
|
||||
{
|
||||
$$= $2;
|
||||
};
|
||||
|
||||
subselect_init:
|
||||
singleval_subselect_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:
|
||||
|
|
Loading…
Reference in a new issue