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

support of simple row subselects (SCRUM)

parent b785e980
......@@ -52,6 +52,54 @@ a
SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NOT NULL;
a
1
SELECT (SELECT 1,2,3) = ROW(1,2,3);
(SELECT 1,2,3) = ROW(1,2,3)
1
SELECT (SELECT 1,2,3) = ROW(1,2,1);
(SELECT 1,2,3) = ROW(1,2,1)
0
SELECT (SELECT 1,2,3) < ROW(1,2,1);
(SELECT 1,2,3) < ROW(1,2,1)
0
SELECT (SELECT 1,2,3) > ROW(1,2,1);
(SELECT 1,2,3) > ROW(1,2,1)
1
SELECT (SELECT 1,2,3) = ROW(1,2,NULL);
(SELECT 1,2,3) = ROW(1,2,NULL)
NULL
SELECT ROW(1,2,3) = (SELECT 1,2,3);
ROW(1,2,3) = (SELECT 1,2,3)
1
SELECT ROW(1,2,3) = (SELECT 1,2,1);
ROW(1,2,3) = (SELECT 1,2,1)
0
SELECT ROW(1,2,3) < (SELECT 1,2,1);
ROW(1,2,3) < (SELECT 1,2,1)
0
SELECT ROW(1,2,3) > (SELECT 1,2,1);
ROW(1,2,3) > (SELECT 1,2,1)
1
SELECT ROW(1,2,3) = (SELECT 1,2,NULL);
ROW(1,2,3) = (SELECT 1,2,NULL)
NULL
SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'a');
(SELECT 1.5,2,'a') = ROW(1.5,2,'a')
1
SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'b');
(SELECT 1.5,2,'a') = ROW(1.5,2,'b')
0
SELECT (SELECT 1.5,2,'a') = ROW('b',2,'b');
(SELECT 1.5,2,'a') = ROW('b',2,'b')
0
SELECT (SELECT 'b',2,'a') = ROW(1.5,2,'a');
(SELECT 'b',2,'a') = ROW(1.5,2,'a')
0
SELECT (SELECT 1.5,2,'a') = ROW(1.5,'c','a');
(SELECT 1.5,2,'a') = ROW(1.5,'c','a')
0
SELECT (SELECT 1.5,'c','a') = ROW(1.5,2,'a');
(SELECT 1.5,'c','a') = ROW(1.5,2,'a')
0
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8;
create table t1 (a int);
create table t2 (a int, b int);
......@@ -602,7 +650,7 @@ CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) TYPE=MyISAM CHARSET=latin
INSERT INTO t1 values (1),(1);
UPDATE t SET id=(SELECT * FROM t1);
Subselect returns more than 1 record
drop table t;
drop table t, t1;
create table t (a int);
insert into t values (1),(2),(3);
select 1 IN (SELECT * from t);
......@@ -705,3 +753,23 @@ select 10.5 > ANY (SELECT * from t);
10.5 > ANY (SELECT * from t)
1
drop table t;
create table t1 (a int, b int, c varchar(10));
create table t2 (a int);
insert into t1 values (1,2,'a'),(2,3,'b'),(3,4,'c');
insert into t2 values (1),(2),(NULL);
select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),(select c from t1 where a=t2.a) from t2;
a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a') (select c from t1 where a=t2.a)
1 1 a
2 0 b
NULL NULL NULL
select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b'),(select c from t1 where a=t2.a) from t2;
a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b') (select c from t1 where a=t2.a)
1 0 a
2 1 b
NULL NULL NULL
select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c'),(select c from t1 where a=t2.a) from t2;
a (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c') (select c from t1 where a=t2.a)
1 0 a
2 0 b
NULL NULL NULL
drop table t1,t2;
......@@ -26,6 +26,22 @@ select (SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE(1));
SELECT 1 FROM (SELECT 1) a PROCEDURE ANALYSE((SELECT 1));
SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NULL;
SELECT (SELECT 1) as a FROM (SELECT 1) b WHERE (SELECT a) IS NOT NULL;
SELECT (SELECT 1,2,3) = ROW(1,2,3);
SELECT (SELECT 1,2,3) = ROW(1,2,1);
SELECT (SELECT 1,2,3) < ROW(1,2,1);
SELECT (SELECT 1,2,3) > ROW(1,2,1);
SELECT (SELECT 1,2,3) = ROW(1,2,NULL);
SELECT ROW(1,2,3) = (SELECT 1,2,3);
SELECT ROW(1,2,3) = (SELECT 1,2,1);
SELECT ROW(1,2,3) < (SELECT 1,2,1);
SELECT ROW(1,2,3) > (SELECT 1,2,1);
SELECT ROW(1,2,3) = (SELECT 1,2,NULL);
SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'a');
SELECT (SELECT 1.5,2,'a') = ROW(1.5,2,'b');
SELECT (SELECT 1.5,2,'a') = ROW('b',2,'b');
SELECT (SELECT 'b',2,'a') = ROW(1.5,2,'a');
SELECT (SELECT 1.5,2,'a') = ROW(1.5,'c','a');
SELECT (SELECT 1.5,'c','a') = ROW(1.5,2,'a');
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8;
create table t1 (a int);
......@@ -363,7 +379,7 @@ CREATE TABLE t1 (id int(11) default NULL, KEY id (id)) TYPE=MyISAM CHARSET=latin
INSERT INTO t1 values (1),(1);
-- error 1240
UPDATE t SET id=(SELECT * FROM t1);
drop table t;
drop table t, t1;
#NULL test
......@@ -409,3 +425,12 @@ select 10.5 > ALL (SELECT * from t);
select 1.5 > ANY (SELECT * from t);
select 10.5 > ANY (SELECT * from t);
drop table t;
create table t1 (a int, b int, c varchar(10));
create table t2 (a int);
insert into t1 values (1,2,'a'),(2,3,'b'),(3,4,'c');
insert into t2 values (1),(2),(NULL);
select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),(select c from t1 where a=t2.a) from t2;
select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,3,'b'),(select c from t1 where a=t2.a) from t2;
select a, (select a,b,c from t1 where t1.a=t2.a) = ROW(a,4,'c'),(select c from t1 where a=t2.a) from t2;
drop table t1,t2;
......@@ -1217,6 +1217,60 @@ bool field_is_equal_to_item(Field *field,Item *item)
return result == field->val_real();
}
Item_cache* Item_cache::get_cache(Item_result type)
{
switch (type)
{
case INT_RESULT:
return new Item_cache_int();
case REAL_RESULT:
return new Item_cache_real();
case STRING_RESULT:
return new Item_cache_str();
default:
// should never be in real life
DBUG_ASSERT(0);
return 0;
}
}
void Item_cache_str::store(Item *item)
{
str_value.set(buffer, sizeof(buffer), item->charset());
value= item->str_result(&str_value);
if ((null_value= item->null_value))
value= 0;
else if (value != &str_value)
{
/*
We copy string value to avoid changing value if 'item' is table field
in queries like following (where t1.c is varchar):
select a,
(select a,b,c from t1 where t1.a=t2.a) = ROW(a,2,'a'),
(select c from t1 where a=t2.a)
from t2;
*/
str_value.copy(*value);
value= &str_value;
}
}
double Item_cache_str::val()
{
if (value)
return my_strntod(value->charset(), value->ptr(),
value->length(), (char**)0);
else
return (double)0;
}
longlong Item_cache_str::val_int()
{
if (value)
return my_strntoll(value->charset(), value->ptr(),
value->length(), (char**) 0, 10);
else
return (longlong)0;
}
/*****************************************************************************
** Instantiate templates
......
......@@ -103,7 +103,9 @@ public:
virtual Item** addr(uint i) { return 0; }
virtual bool check_cols(uint c);
// It is not row => null inside is impossible
virtual bool null_inside() { return 0; };
virtual bool null_inside() { return 0; }
// used in row subselects to get value of elements
virtual void bring_value() {}
};
......@@ -719,6 +721,7 @@ public:
decimals= dec;
}
enum Type type() const { return CACHE_ITEM; }
static Item_cache* get_cache(Item_result type);
};
class Item_cache_int: public Item_cache
......@@ -766,24 +769,9 @@ class Item_cache_str: public Item_cache
public:
Item_cache_str() { fixed= 1; null_value= 1; }
void store(Item *item)
{
str_value.set(buffer, sizeof(buffer), item->charset());
value= item->str_result(&str_value);
// TODO remove if str_value charset have no side effect for now
str_value.set_charset(value->charset());
null_value= item->null_value;
}
double val()
{
return my_strntod(value->charset(), value->ptr(),
value->length(), (char**)0);
}
longlong val_int()
{
return my_strntoll(value->charset(), value->ptr(),
value->length(), (char**) 0, 10);
}
void store(Item *item);
double val();
longlong val_int();
String* val_str(String *) { return value; }
enum Item_result result_type() const { return STRING_RESULT; }
CHARSET_INFO *charset() const { return value->charset(); };
......
......@@ -247,6 +247,8 @@ int Arg_comparator::compare_e_int()
int Arg_comparator::compare_row()
{
int res= 0;
(*a)->bring_value();
(*b)->bring_value();
uint n= (*a)->cols();
for (uint i= 0; i<n; i++)
{
......@@ -261,6 +263,8 @@ int Arg_comparator::compare_row()
int Arg_comparator::compare_e_row()
{
int res= 0;
(*a)->bring_value();
(*b)->bring_value();
uint n= (*a)->cols();
for (uint i= 0; i<n; i++)
{
......@@ -1219,6 +1223,7 @@ void cmp_item_row::store_value(Item *item)
n= item->cols();
if ((comparators= (cmp_item **) thd->alloc(sizeof(cmp_item *)*n)))
{
item->bring_value();
item->null_value= 0;
for (uint i=0; i < n; i++)
if ((comparators[i]= cmp_item::get_comparator(item->el(i))))
......@@ -1252,6 +1257,7 @@ void cmp_item_row::store_value_by_template(cmp_item *t, Item *item)
n= tmpl->n;
if ((comparators= (cmp_item **) sql_alloc(sizeof(cmp_item *)*n)))
{
item->bring_value();
item->null_value= 0;
for (uint i=0; i < n; i++)
if ((comparators[i]= tmpl->comparators[i]->make_same()))
......@@ -1284,6 +1290,7 @@ int cmp_item_row::cmp(Item *arg)
return 1;
}
bool was_null= 0;
arg->bring_value();
for (uint i=0; i < n; i++)
if (comparators[i]->cmp(arg->el(i)))
{
......
......@@ -112,9 +112,14 @@ bool Item_subselect::check_loop(uint id)
DBUG_RETURN(engine->check_loop(id));
}
Item::Type Item_subselect::type() const
{
return SUBSELECT_ITEM;
}
void Item_subselect::fix_length_and_dec()
{
engine->fix_length_and_dec();
engine->fix_length_and_dec(0);
}
inline table_map Item_subselect::used_tables() const
......@@ -130,6 +135,7 @@ Item_singleval_subselect::Item_singleval_subselect(THD *thd,
init(thd, select_lex, new select_singleval_subselect(this));
max_columns= 1;
maybe_null= 1;
max_columns= UINT_MAX;
DBUG_VOID_RETURN;
}
......@@ -140,9 +146,9 @@ void Item_singleval_subselect::reset()
value->null_value= 1;
}
void Item_singleval_subselect::store(Item *item)
void Item_singleval_subselect::store(uint i, Item *item)
{
value->store(item);
row[i]->store(item);
}
enum Item_result Item_singleval_subselect::result_type() const
......@@ -152,29 +158,58 @@ enum Item_result Item_singleval_subselect::result_type() const
void Item_singleval_subselect::fix_length_and_dec()
{
engine->fix_length_and_dec();
switch (engine->type())
if ((max_columns= engine->cols()) == 1)
{
engine->fix_length_and_dec(row= &value);
if (!(value= Item_cache::get_cache(engine->type())))
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
current_thd->fatal_error= 1;
return;
}
}
else
{
case INT_RESULT:
value= new Item_cache_int();
break;
case REAL_RESULT:
value= new Item_cache_real();
break;
case STRING_RESULT:
value= new Item_cache_str();
break;
default:
// should never be in real life
DBUG_ASSERT(0);
return;
THD *thd= current_thd;
if (!(row= (Item_cache**)thd->alloc(sizeof(Item_cache*)*max_columns)))
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
thd->fatal_error= 1;
return;
}
engine->fix_length_and_dec(row);
value= *row;
}
value->set_len_n_dec(max_length, decimals);
}
Item::Type Item_subselect::type() const
uint Item_singleval_subselect::cols()
{
return SUBSELECT_ITEM;
return engine->cols();
}
bool Item_singleval_subselect::check_cols(uint c)
{
if (c != engine->cols())
{
my_error(ER_CARDINALITY_COL, MYF(0), c);
return 1;
}
return 0;
}
bool Item_singleval_subselect::null_inside()
{
for (uint i= 0; i < max_columns ; i++)
{
if (row[i]->null_value)
return 1;
}
return 0;
}
void Item_singleval_subselect::bring_value()
{
engine->exec();
}
double Item_singleval_subselect::val ()
......@@ -268,7 +303,7 @@ Item_allany_subselect::Item_allany_subselect(THD *thd, Item * left_exp,
void Item_exists_subselect::fix_length_and_dec()
{
decimals=0;
decimals= 0;
max_length= 1;
}
......@@ -540,31 +575,85 @@ int subselect_union_engine::prepare()
return unit->prepare(thd, result);
}
void subselect_single_select_engine::fix_length_and_dec()
static Item_result set_row(SELECT_LEX *select_lex, Item * item,
Item_cache **row)
{
Item_result res_type= STRING_RESULT;
Item *sel_item;
List_iterator_fast<Item> li(select_lex->item_list);
Item *sel_item= li++;
item->max_length= sel_item->max_length;
res_type= sel_item->result_type();
item->decimals= sel_item->decimals;
for (uint i= 0; (sel_item= li++); i++)
{
item->max_length= sel_item->max_length;
res_type= sel_item->result_type();
item->decimals= sel_item->decimals;
if (row)
{
if (!(row[i]= Item_cache::get_cache(res_type)))
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
current_thd->fatal_error= 1;
return STRING_RESULT; // we should return something
}
row[i]->set_len_n_dec(sel_item->max_length, sel_item->decimals);
}
}
if (select_lex->item_list.elements > 1)
res_type= ROW_RESULT;
return res_type;
}
void subselect_union_engine::fix_length_and_dec()
void subselect_single_select_engine::fix_length_and_dec(Item_cache **row)
{
uint32 mlen= 0, len;
Item *sel_item= 0;
for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
DBUG_ASSERT(row || select_lex->item_list.elements==1);
res_type= set_row(select_lex, item, row);
}
void subselect_union_engine::fix_length_and_dec(Item_cache **row)
{
DBUG_ASSERT(row || unit->first_select()->item_list.elements==1);
if (unit->first_select()->item_list.elements == 1)
{
List_iterator_fast<Item> li(sl->item_list);
Item *s_item= li++;
if ((len= s_item->max_length))
mlen= len;
if (!sel_item)
sel_item= s_item;
uint32 mlen= 0, len;
Item *sel_item= 0;
for (SELECT_LEX *sl= unit->first_select(); sl; sl= sl->next_select())
{
List_iterator_fast<Item> li(sl->item_list);
Item *s_item= li++;
if ((len= s_item->max_length) > mlen)
mlen= len;
if (!sel_item)
sel_item= s_item;
}
item->max_length= mlen;
res_type= sel_item->result_type();
item->decimals= sel_item->decimals;
if (row)
{
if (!(row[0]= Item_cache::get_cache(res_type)))
{
my_message(ER_OUT_OF_RESOURCES, ER(ER_OUT_OF_RESOURCES), MYF(0));
current_thd->fatal_error= 1;
return;
}
row[0]->set_len_n_dec(mlen, sel_item->decimals);
}
}
else
{
SELECT_LEX *sl= unit->first_select();
res_type= set_row(sl, item, row);
for(sl= sl->next_select(); sl; sl->next_select())
{
List_iterator_fast<Item> li(sl->item_list);
Item *sel_item;
for (uint i= 0; (sel_item= li++); i++)
{
if (sel_item->max_length > row[i]->max_length)
row[i]->max_length= sel_item->max_length;
}
}
}
item->max_length= mlen;
res_type= sel_item->result_type();
item->decimals= sel_item->decimals;
}
int subselect_single_select_engine::exec()
......
......@@ -94,8 +94,7 @@ class Item_cache;
class Item_singleval_subselect :public Item_subselect
{
protected:
Item_cache *value;
Item_cache *value, **row;
public:
Item_singleval_subselect(THD *thd, st_select_lex *select_lex);
Item_singleval_subselect(Item_singleval_subselect *item):
......@@ -106,7 +105,7 @@ public:
decimals= item->decimals;
}
void reset();
void store(Item* item);
void store(uint i, Item* item);
double val();
longlong val_int ();
String *val_str (String *);
......@@ -114,6 +113,13 @@ public:
enum Item_result result_type() const;
void fix_length_and_dec();
uint cols();
Item* el(uint i) { return (Item*)row[i]; }
Item** addr(uint i) { return (Item**)row + i; }
bool check_cols(uint c);
bool null_inside();
void bring_value();
friend class select_singleval_subselect;
};
......@@ -212,7 +218,7 @@ public:
}
virtual int prepare()= 0;
virtual void fix_length_and_dec()= 0;
virtual void fix_length_and_dec(Item_cache** row)= 0;
virtual int exec()= 0;
virtual uint cols()= 0; /* return number of columnss in select */
virtual bool depended()= 0; /* depended from outer select */
......@@ -233,7 +239,7 @@ public:
select_subselect *result,
Item_subselect *item);
int prepare();
void fix_length_and_dec();
void fix_length_and_dec(Item_cache** row);
int exec();
uint cols();
bool depended();
......@@ -250,7 +256,7 @@ public:
select_subselect *result,
Item_subselect *item);
int prepare();
void fix_length_and_dec();
void fix_length_and_dec(Item_cache** row);
int exec();
uint cols();
bool depended();
......
......@@ -931,8 +931,9 @@ bool select_singleval_subselect::send_data(List<Item> &items)
DBUG_RETURN(0);
}
List_iterator_fast<Item> li(items);
Item *val_item= li++; // Only one (single value subselect)
it->store(val_item);
Item *val_item;
for (uint i= 0; (val_item= li++); i++)
it->store(i, val_item);
it->assigned(1);
DBUG_RETURN(0);
}
......
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