mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge sanja.is.com.ua:/home/bell/mysql/mysql-4.1
into sanja.is.com.ua:/home/bell/mysql/work-in-4.1
This commit is contained in:
@ -99,6 +99,17 @@ select * from t3 where not exists (select * from t2 where t2.b=t3.a);
|
||||
a
|
||||
6
|
||||
3
|
||||
select * from t3 where a in (select b from t2);
|
||||
a
|
||||
7
|
||||
select * from t3 where a not in (select b from t2);
|
||||
a
|
||||
6
|
||||
3
|
||||
select * from t3 where a in (select a,b from t2);
|
||||
Subselect returns more than 1 field
|
||||
select * from t3 where a in (select * from t2);
|
||||
Subselect returns more than 1 field
|
||||
insert into t4 values (12,7),(1,7),(10,9),(9,6),(7,6),(3,9);
|
||||
select b,max(a) as ma from t4 group by b having b < (select max(t2.a)
|
||||
from t2 where t2.b=t4.b);
|
||||
|
@ -34,6 +34,12 @@ select b,(select avg(t2.a+(select min(t3.a) from t3 where t3.a >= t4.a)) from t2
|
||||
explain 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);
|
||||
select * from t3 where a in (select b from t2);
|
||||
select * from t3 where a not in (select b from t2);
|
||||
-- error 1239
|
||||
select * from t3 where a in (select a,b from t2);
|
||||
-- error 1239
|
||||
select * from t3 where a in (select * from t2);
|
||||
insert into t4 values (12,7),(1,7),(10,9),(9,6),(7,6),(3,9);
|
||||
select b,max(a) as ma from t4 group by b having b < (select max(t2.a)
|
||||
from t2 where t2.b=t4.b);
|
||||
|
47
sql/item.cc
47
sql/item.cc
@ -424,6 +424,53 @@ bool Item::fix_fields(THD *thd,
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool Item_outer_select_context_saver::fix_fields(THD *thd,
|
||||
struct st_table_list *list,
|
||||
Item ** ref)
|
||||
{
|
||||
DBUG_ENTER("Item_outer_select_context_saver::fix_fields");
|
||||
bool res= item->fix_fields(thd,
|
||||
0, // do not show current subselect fields
|
||||
&item);
|
||||
*ref= item;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
bool Item_asterisk_remover::fix_fields(THD *thd,
|
||||
struct st_table_list *list,
|
||||
Item ** ref)
|
||||
{
|
||||
DBUG_ENTER("Item_asterisk_remover::fix_fields");
|
||||
|
||||
bool res;
|
||||
if (item)
|
||||
if (item->type() == Item::FIELD_ITEM &&
|
||||
((Item_field*) item)->field_name[0] == '*')
|
||||
{
|
||||
List<Item> fields;
|
||||
fields.push_back(item);
|
||||
List_iterator<Item> it(fields);
|
||||
it++;
|
||||
uint elem=fields.elements;
|
||||
if (insert_fields(thd, list, ((Item_field*) item)->db_name,
|
||||
((Item_field*) item)->table_name, &it))
|
||||
res= -1;
|
||||
else
|
||||
if (fields.elements > 1)
|
||||
{
|
||||
my_message(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0));
|
||||
res= -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
res= item->fix_fields(thd, list, &item);
|
||||
else
|
||||
res= -1;
|
||||
*ref= item;
|
||||
DBUG_RETURN(res);
|
||||
}
|
||||
|
||||
|
||||
bool Item_field::fix_fields(THD *thd, TABLE_LIST *tables, Item **ref)
|
||||
{
|
||||
if (!field) // If field is not checked
|
||||
|
49
sql/item.h
49
sql/item.h
@ -90,6 +90,55 @@ public:
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Wrapper base class
|
||||
*/
|
||||
|
||||
class Item_wrapper :public Item
|
||||
{
|
||||
protected:
|
||||
Item *item;
|
||||
public:
|
||||
/*
|
||||
Following methods should not be used, because fix_fields exclude this
|
||||
item (it assign '*ref' with field 'item' in derived classes)
|
||||
*/
|
||||
enum Type type() const { return item->type(); }
|
||||
double val() { return item->val(); }
|
||||
longlong val_int() { return item->val_int(); }
|
||||
String* val_str(String* s) { return item->val_str(s); }
|
||||
void make_field(Send_field* f) { item->make_field(f); }
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Save context of name resolution for Item, used in subselect transformer.
|
||||
*/
|
||||
class Item_outer_select_context_saver :public Item_wrapper
|
||||
{
|
||||
Item *item;
|
||||
public:
|
||||
Item_outer_select_context_saver(Item *i):
|
||||
item(i)
|
||||
{
|
||||
}
|
||||
bool fix_fields(THD *, struct st_table_list *, Item ** ref);
|
||||
};
|
||||
|
||||
/*
|
||||
To resolve '*' field moved to condition
|
||||
*/
|
||||
class Item_asterisk_remover :public Item_wrapper
|
||||
{
|
||||
Item *item;
|
||||
public:
|
||||
Item_asterisk_remover(Item *i):
|
||||
item(i)
|
||||
{
|
||||
}
|
||||
bool fix_fields(THD *, struct st_table_list *, Item ** ref);
|
||||
};
|
||||
|
||||
class st_select_lex;
|
||||
class Item_ident :public Item
|
||||
{
|
||||
|
@ -44,12 +44,13 @@ Item_subselect::Item_subselect():
|
||||
}
|
||||
|
||||
void Item_subselect::init(THD *thd, st_select_lex *select_lex,
|
||||
select_subselect *result)
|
||||
select_subselect *result, Item *left_expr)
|
||||
{
|
||||
|
||||
DBUG_ENTER("Item_subselect::init");
|
||||
DBUG_PRINT("subs", ("select_lex 0x%xl", (long) select_lex));
|
||||
DBUG_PRINT("subs", ("select_lex 0x%xl", (ulong) select_lex));
|
||||
|
||||
select_transformer(select_lex, left_expr);
|
||||
if (select_lex->next_select())
|
||||
engine= new subselect_union_engine(thd, select_lex->master_unit(), result,
|
||||
this);
|
||||
@ -65,6 +66,14 @@ Item_subselect::~Item_subselect()
|
||||
delete engine;
|
||||
}
|
||||
|
||||
void Item_subselect::select_transformer(st_select_lex *select_lex,
|
||||
Item *left_expr)
|
||||
{
|
||||
DBUG_ENTER("Item_subselect::select_transformer");
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
void Item_subselect::make_field (Send_field *tmp_field)
|
||||
{
|
||||
if (null_value)
|
||||
@ -109,9 +118,11 @@ Item_singleval_subselect::Item_singleval_subselect(THD *thd,
|
||||
st_select_lex *select_lex):
|
||||
Item_subselect()
|
||||
{
|
||||
init(thd, select_lex, new select_singleval_subselect(this));
|
||||
DBUG_ENTER("Item_singleval_subselect::Item_singleval_subselect");
|
||||
init(thd, select_lex, new select_singleval_subselect(this), 0);
|
||||
max_columns= 1;
|
||||
maybe_null= 1;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
void Item_singleval_subselect::fix_length_and_dec()
|
||||
@ -156,17 +167,37 @@ String *Item_singleval_subselect::val_str (String *str)
|
||||
}
|
||||
|
||||
Item_exists_subselect::Item_exists_subselect(THD *thd,
|
||||
st_select_lex *select_lex):
|
||||
st_select_lex *select_lex,
|
||||
Item *left_expr):
|
||||
Item_subselect()
|
||||
{
|
||||
init(thd, select_lex, new select_exists_subselect(this));
|
||||
DBUG_ENTER("Item_exists_subselect::Item_exists_subselect");
|
||||
init(thd, select_lex, new select_exists_subselect(this), left_expr);
|
||||
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
|
||||
// We need only 1 row to determinate existence
|
||||
select_lex->master_unit()->global_parameters->select_limit= 1;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
Item_in_subselect::Item_in_subselect(THD *thd, Item * left_expr,
|
||||
st_select_lex *select_lex):
|
||||
Item_exists_subselect()
|
||||
{
|
||||
DBUG_ENTER("Item_in_subselect::Item_in_subselect");
|
||||
init(thd, select_lex, new select_exists_subselect(this), left_expr);
|
||||
max_columns= UINT_MAX;
|
||||
null_value= 0; //can't be NULL
|
||||
maybe_null= 0; //can't be NULL
|
||||
value= 0;
|
||||
// We need only 1 row to determinate existence
|
||||
select_lex->master_unit()->global_parameters->select_limit= 1;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
||||
void Item_exists_subselect::fix_length_and_dec()
|
||||
{
|
||||
max_length= 1;
|
||||
@ -204,6 +235,37 @@ String *Item_exists_subselect::val_str(String *str)
|
||||
return str;
|
||||
}
|
||||
|
||||
Item_in_subselect::Item_in_subselect(Item_in_subselect *item):
|
||||
Item_exists_subselect(item)
|
||||
{
|
||||
}
|
||||
|
||||
void Item_in_subselect::select_transformer(st_select_lex *select_lex,
|
||||
Item *left_expr)
|
||||
{
|
||||
DBUG_ENTER("Item_in_subselect::select_transformer");
|
||||
for(SELECT_LEX * sl= select_lex; sl; sl= sl->next_select())
|
||||
{
|
||||
Item *item;
|
||||
if (sl->item_list.elements > 1)
|
||||
{
|
||||
my_message(ER_SUBSELECT_NO_1_COL, ER(ER_SUBSELECT_NO_1_COL), MYF(0));
|
||||
item= 0; // Item_asterisk_remover mast fail
|
||||
}
|
||||
else
|
||||
item= (Item*) sl->item_list.pop();
|
||||
sl->item_list.empty();
|
||||
sl->item_list.push_back(new Item_int(1));
|
||||
left_expr= new Item_outer_select_context_saver(left_expr);
|
||||
item= new Item_asterisk_remover(item);
|
||||
if (sl->where)
|
||||
sl->where= new Item_cond_and(sl->where,
|
||||
new Item_func_eq(item, left_expr));
|
||||
else
|
||||
sl->where= new Item_func_eq(item, left_expr);
|
||||
}
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
subselect_single_select_engine::subselect_single_select_engine(THD *thd,
|
||||
st_select_lex *select,
|
||||
|
@ -55,13 +55,16 @@ public:
|
||||
pointer in constructor initialization list, but we need pass pointer
|
||||
to subselect Item class to select_subselect classes constructor.
|
||||
*/
|
||||
void init (THD *thd, st_select_lex *select_lex, select_subselect *result);
|
||||
virtual void init (THD *thd, st_select_lex *select_lex,
|
||||
select_subselect *result,
|
||||
Item *left_expr= 0);
|
||||
|
||||
~Item_subselect();
|
||||
virtual void assign_null()
|
||||
{
|
||||
null_value= 1;
|
||||
}
|
||||
virtual void select_transformer(st_select_lex *select_lex, Item *left_expr);
|
||||
bool assigned() { return value_assigned; }
|
||||
void assigned(bool a) { value_assigned= a; }
|
||||
enum Type type() const;
|
||||
@ -74,7 +77,6 @@ public:
|
||||
friend class select_subselect;
|
||||
};
|
||||
|
||||
|
||||
/* single value subselect */
|
||||
|
||||
class Item_singleval_subselect :public Item_subselect
|
||||
@ -127,12 +129,15 @@ protected:
|
||||
longlong value; /* value of this item (boolean: exists/not-exists) */
|
||||
|
||||
public:
|
||||
Item_exists_subselect(THD *thd, st_select_lex *select_lex);
|
||||
Item_exists_subselect(THD *thd, st_select_lex *select_lex,
|
||||
Item *left_expr= 0);
|
||||
Item_exists_subselect(Item_exists_subselect *item):
|
||||
Item_subselect(item)
|
||||
{
|
||||
value= item->value;
|
||||
}
|
||||
Item_exists_subselect(): Item_subselect() {}
|
||||
|
||||
virtual void assign_null()
|
||||
{
|
||||
value= 0;
|
||||
@ -147,6 +152,16 @@ public:
|
||||
friend class select_exists_subselect;
|
||||
};
|
||||
|
||||
/* IN subselect */
|
||||
|
||||
class Item_in_subselect :public Item_exists_subselect
|
||||
{
|
||||
public:
|
||||
Item_in_subselect(THD *thd, Item * left_expr, st_select_lex *select_lex);
|
||||
Item_in_subselect(Item_in_subselect *item);
|
||||
virtual void select_transformer(st_select_lex *select_lex, Item *left_exp);
|
||||
};
|
||||
|
||||
class subselect_engine
|
||||
{
|
||||
protected:
|
||||
|
@ -70,6 +70,7 @@ inline Item *or_or_concat(Item* A, Item* B)
|
||||
enum Item_udftype udf_type;
|
||||
CHARSET_INFO *charset;
|
||||
interval_type interval;
|
||||
st_select_lex *select_lex;
|
||||
}
|
||||
|
||||
%{
|
||||
@ -530,7 +531,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
||||
|
||||
%type <lex_str>
|
||||
IDENT TEXT_STRING REAL_NUM FLOAT_NUM NUM LONG_NUM HEX_NUM LEX_HOSTNAME
|
||||
ULONGLONG_NUM field_ident select_alias ident ident_or_text UNDERSCORE_CHARSET
|
||||
ULONGLONG_NUM field_ident select_alias ident ident_or_text
|
||||
UNDERSCORE_CHARSET
|
||||
|
||||
%type <lex_str_ptr>
|
||||
opt_table_alias
|
||||
@ -612,6 +614,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
||||
|
||||
%type <variable> internal_variable_name
|
||||
|
||||
%type <select_lex> in_subselect in_subselect_init
|
||||
|
||||
%type <NONE>
|
||||
query verb_clause create change select do drop insert replace insert2
|
||||
insert_values update delete truncate rename
|
||||
@ -1719,10 +1723,16 @@ expr: expr_expr { $$= $1; }
|
||||
|
||||
/* expressions that begin with 'expr' */
|
||||
expr_expr:
|
||||
expr IN_SYM '(' expr_list ')'
|
||||
expr IN_SYM '(' expr_list ')'
|
||||
{ $$= new Item_func_in($1,*$4); }
|
||||
| expr NOT IN_SYM '(' expr_list ')'
|
||||
{ $$= new Item_func_not(new Item_func_in($1,*$5)); }
|
||||
| expr IN_SYM in_subselect
|
||||
{ $$= new Item_in_subselect(current_thd, $1, $3); }
|
||||
| expr NOT IN_SYM in_subselect
|
||||
{
|
||||
$$= new Item_func_not(new Item_in_subselect(current_thd, $1, $4));
|
||||
}
|
||||
| expr BETWEEN_SYM no_and_expr AND expr
|
||||
{ $$= new Item_func_between($1,$3,$5); }
|
||||
| expr NOT BETWEEN_SYM no_and_expr AND expr
|
||||
@ -1802,10 +1812,16 @@ no_in_expr:
|
||||
|
||||
/* expressions that begin with 'expr' that does NOT follow AND */
|
||||
no_and_expr:
|
||||
no_and_expr IN_SYM '(' expr_list ')'
|
||||
{ $$= new Item_func_in($1,*$4); }
|
||||
no_and_expr IN_SYM '(' expr_list ')'
|
||||
{ $$= new Item_func_in($1,*$4); }
|
||||
| no_and_expr NOT IN_SYM '(' expr_list ')'
|
||||
{ $$= new Item_func_not(new Item_func_in($1,*$5)); }
|
||||
| no_and_expr IN_SYM in_subselect
|
||||
{ $$= new Item_in_subselect(current_thd, $1, $3); }
|
||||
| no_and_expr NOT IN_SYM in_subselect
|
||||
{
|
||||
$$= new Item_func_not(new Item_in_subselect(current_thd, $1, $4));
|
||||
}
|
||||
| no_and_expr BETWEEN_SYM no_and_expr AND expr
|
||||
{ $$= new Item_func_between($1,$3,$5); }
|
||||
| no_and_expr NOT BETWEEN_SYM no_and_expr AND expr
|
||||
@ -4193,6 +4209,19 @@ exists_subselect_init:
|
||||
Lex->select->master_unit()->first_select());
|
||||
};
|
||||
|
||||
in_subselect:
|
||||
subselect_start in_subselect_init
|
||||
subselect_end
|
||||
{
|
||||
$$= $2;
|
||||
};
|
||||
|
||||
in_subselect_init:
|
||||
select_init
|
||||
{
|
||||
$$= Lex->select->master_unit()->first_select();
|
||||
};
|
||||
|
||||
subselect_start:
|
||||
'('
|
||||
{
|
||||
|
Reference in New Issue
Block a user