mirror of
https://github.com/MariaDB/server.git
synced 2025-08-01 03:47:19 +03:00
fixed bug 185 (constant IN (SELECT field ...) do not return NULL correctly)
mysql-test/r/subselect.result: new test results test of bug 185 mysql-test/t/subselect.test: test of bug 185 sql/item.h: new method sql/item_cmpfunc.cc: new Item to control NULL value in HAVING clouse sql/item_cmpfunc.h: new Item to control NULL value in HAVING clouse sql/item_subselect.cc: if IN was rewrited through WHERE thien it will be rewrited in following way: WHERE left_expr=item or is null(item) heving is_not_null_test(item) sql/item_subselect.h: Item_is_not_null_test can change was_null flag sql/sql_select.cc: some layout fix
This commit is contained in:
@ -810,7 +810,7 @@ a t1.a in (select t2.a from t2)
|
|||||||
explain SELECT t1.a, t1.a in (select t2.a from t2) FROM t1;
|
explain SELECT t1.a, t1.a in (select t2.a from t2) FROM t1;
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index
|
1 PRIMARY t1 index NULL PRIMARY 4 NULL 4 Using index
|
||||||
2 DEPENDENT SUBQUERY t2 index NULL a 5 NULL 3 Using where; Using index
|
2 DEPENDENT SUBQUERY t2 index a a 5 NULL 3 Using where; Using index
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
create table t1 (a float);
|
create table t1 (a float);
|
||||||
select 10.5 IN (SELECT * from t1 LIMIT 1);
|
select 10.5 IN (SELECT * from t1 LIMIT 1);
|
||||||
@ -1062,7 +1062,7 @@ SELECT 0 IN (SELECT 1 FROM t1 a);
|
|||||||
EXPLAIN SELECT 0 IN (SELECT 1 FROM t1 a);
|
EXPLAIN SELECT 0 IN (SELECT 1 FROM t1 a);
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
|
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||||
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
INSERT INTO t1 (pseudo) VALUES ('test1');
|
INSERT INTO t1 (pseudo) VALUES ('test1');
|
||||||
SELECT 0 IN (SELECT 1 FROM t1 a);
|
SELECT 0 IN (SELECT 1 FROM t1 a);
|
||||||
0 IN (SELECT 1 FROM t1 a)
|
0 IN (SELECT 1 FROM t1 a)
|
||||||
@ -1070,7 +1070,7 @@ SELECT 0 IN (SELECT 1 FROM t1 a);
|
|||||||
EXPLAIN SELECT 0 IN (SELECT 1 FROM t1 a);
|
EXPLAIN SELECT 0 IN (SELECT 1 FROM t1 a);
|
||||||
id select_type table type possible_keys key key_len ref rows Extra
|
id select_type table type possible_keys key key_len ref rows Extra
|
||||||
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
|
1 PRIMARY NULL NULL NULL NULL NULL NULL NULL No tables used
|
||||||
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE
|
2 DEPENDENT SUBQUERY NULL NULL NULL NULL NULL NULL NULL Impossible WHERE noticed after reading const tables
|
||||||
drop table t1;
|
drop table t1;
|
||||||
CREATE TABLE `t1` (
|
CREATE TABLE `t1` (
|
||||||
`i` int(11) NOT NULL default '0',
|
`i` int(11) NOT NULL default '0',
|
||||||
@ -1099,3 +1099,9 @@ id name
|
|||||||
2 lenka
|
2 lenka
|
||||||
1 lenka
|
1 lenka
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
|
create table t1 (a int, unique index indexa (a));
|
||||||
|
insert into t1 values (-1), (-4), (-2), (NULL);
|
||||||
|
select -10 IN (select a from t1 FORCE INDEX (indexa));
|
||||||
|
-10 IN (select a from t1 FORCE INDEX (indexa))
|
||||||
|
NULL
|
||||||
|
drop table t1;
|
||||||
|
@ -690,3 +690,11 @@ INSERT INTO t2 VALUES (4,'vita'), (1,'vita'), (2,'vita'), (1,'vita');
|
|||||||
update t1, t2 set t2.name='lenka' where t2.id in (select id from t1);
|
update t1, t2 set t2.name='lenka' where t2.id in (select id from t1);
|
||||||
select * from t2;
|
select * from t2;
|
||||||
drop table t1,t2;
|
drop table t1,t2;
|
||||||
|
|
||||||
|
#
|
||||||
|
# correct NULL in <CONSTANT> IN (SELECT ...)
|
||||||
|
#
|
||||||
|
create table t1 (a int, unique index indexa (a));
|
||||||
|
insert into t1 values (-1), (-4), (-2), (NULL);
|
||||||
|
select -10 IN (select a from t1 FORCE INDEX (indexa));
|
||||||
|
drop table t1;
|
||||||
|
@ -603,6 +603,7 @@ public:
|
|||||||
item(it)
|
item(it)
|
||||||
{}
|
{}
|
||||||
bool fix_fields(THD *, struct st_table_list *, Item ** ref);
|
bool fix_fields(THD *, struct st_table_list *, Item ** ref);
|
||||||
|
Item **storage() {return &item;}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1781,6 +1781,43 @@ longlong Item_func_isnull::val_int()
|
|||||||
return args[0]->is_null() ? 1: 0;
|
return args[0]->is_null() ? 1: 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
longlong Item_is_not_null_test::val_int()
|
||||||
|
{
|
||||||
|
DBUG_ENTER("Item_is_not_null_test::val_int");
|
||||||
|
if (!used_tables_cache)
|
||||||
|
{
|
||||||
|
owner->was_null|= (!cached_value);
|
||||||
|
DBUG_PRINT("info", ("cached :%d", cached_value));
|
||||||
|
DBUG_RETURN(cached_value);
|
||||||
|
}
|
||||||
|
if (args[0]->is_null())
|
||||||
|
{
|
||||||
|
DBUG_PRINT("info", ("null"))
|
||||||
|
owner->was_null|= 1;
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Optimize case of not_null_column IS NULL */
|
||||||
|
void Item_is_not_null_test::update_used_tables()
|
||||||
|
{
|
||||||
|
if (!args[0]->maybe_null)
|
||||||
|
{
|
||||||
|
used_tables_cache= 0; /* is always true */
|
||||||
|
cached_value= (longlong) 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
args[0]->update_used_tables();
|
||||||
|
if (!(used_tables_cache=args[0]->used_tables()))
|
||||||
|
{
|
||||||
|
/* Remember if the value is always NULL or never NULL */
|
||||||
|
cached_value= (longlong) !args[0]->is_null();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
longlong Item_func_isnotnull::val_int()
|
longlong Item_func_isnotnull::val_int()
|
||||||
{
|
{
|
||||||
|
@ -648,6 +648,7 @@ class Item_func_in :public Item_int_func
|
|||||||
|
|
||||||
class Item_func_isnull :public Item_bool_func
|
class Item_func_isnull :public Item_bool_func
|
||||||
{
|
{
|
||||||
|
protected:
|
||||||
longlong cached_value;
|
longlong cached_value;
|
||||||
public:
|
public:
|
||||||
Item_func_isnull(Item *a) :Item_bool_func(a) {}
|
Item_func_isnull(Item *a) :Item_bool_func(a) {}
|
||||||
@ -656,11 +657,11 @@ public:
|
|||||||
void fix_length_and_dec()
|
void fix_length_and_dec()
|
||||||
{
|
{
|
||||||
decimals=0; max_length=1; maybe_null=0;
|
decimals=0; max_length=1; maybe_null=0;
|
||||||
Item_func_isnull::update_used_tables();
|
update_used_tables();
|
||||||
}
|
}
|
||||||
const char *func_name() const { return "isnull"; }
|
const char *func_name() const { return "isnull"; }
|
||||||
/* Optimize case of not_null_column IS NULL */
|
/* Optimize case of not_null_column IS NULL */
|
||||||
void update_used_tables()
|
virtual void update_used_tables()
|
||||||
{
|
{
|
||||||
if (!args[0]->maybe_null)
|
if (!args[0]->maybe_null)
|
||||||
{
|
{
|
||||||
@ -680,6 +681,22 @@ public:
|
|||||||
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
|
optimize_type select_optimize() const { return OPTIMIZE_NULL; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* Functions used by HAVING for rewriting IN subquery */
|
||||||
|
|
||||||
|
class Item_in_subselect;
|
||||||
|
class Item_is_not_null_test :public Item_func_isnull
|
||||||
|
{
|
||||||
|
Item_in_subselect* owner;
|
||||||
|
public:
|
||||||
|
Item_is_not_null_test(Item_in_subselect* ow, Item *a)
|
||||||
|
:Item_func_isnull(a), owner(ow)
|
||||||
|
{}
|
||||||
|
longlong val_int();
|
||||||
|
const char *func_name() const { return "is_not_null_test"; }
|
||||||
|
void update_used_tables();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
class Item_func_isnotnull :public Item_bool_func
|
class Item_func_isnotnull :public Item_bool_func
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -508,9 +508,31 @@ void Item_in_subselect::single_value_transformer(THD *thd,
|
|||||||
sl->item_list.push_back(new Item_int("Not_used", (longlong) 1, 21));
|
sl->item_list.push_back(new Item_int("Not_used", (longlong) 1, 21));
|
||||||
if (sl->table_list.elements)
|
if (sl->table_list.elements)
|
||||||
{
|
{
|
||||||
item= (*func)(expr, new Item_asterisk_remover(this, item,
|
Item *having= item, *isnull= item;
|
||||||
(char *)"<no matter>",
|
if (item->type() == Item::FIELD_ITEM &&
|
||||||
(char*)"<result>"));
|
((Item_field*) item)->field_name[0] == '*')
|
||||||
|
{
|
||||||
|
Item_asterisk_remover *remover;
|
||||||
|
item= remover= new Item_asterisk_remover(this, item,
|
||||||
|
(char*)"<no matter>",
|
||||||
|
(char*)"<result>");
|
||||||
|
having=
|
||||||
|
new Item_is_not_null_test(this,
|
||||||
|
new Item_ref(remover->storage(),
|
||||||
|
(char*)"<no matter>",
|
||||||
|
(char*)"<null test>"));
|
||||||
|
isnull=
|
||||||
|
new Item_is_not_null_test(this,
|
||||||
|
new Item_ref(remover->storage(),
|
||||||
|
(char*)"<no matter>",
|
||||||
|
(char*)"<null test>"));
|
||||||
|
}
|
||||||
|
having= new Item_is_not_null_test(this, having);
|
||||||
|
sl->having= (sl->having ?
|
||||||
|
new Item_cond_and(having, sl->having) :
|
||||||
|
having);
|
||||||
|
item= new Item_cond_or((*func)(expr, item),
|
||||||
|
new Item_func_isnull(isnull));
|
||||||
sl->where= and_items(sl->where, item);
|
sl->where= and_items(sl->where, item);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -183,6 +183,7 @@ public:
|
|||||||
|
|
||||||
friend class Item_asterisk_remover;
|
friend class Item_asterisk_remover;
|
||||||
friend class Item_ref_null_helper;
|
friend class Item_ref_null_helper;
|
||||||
|
friend class Item_is_not_null_test;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* ALL/ANY/SOME subselect */
|
/* ALL/ANY/SOME subselect */
|
||||||
|
@ -299,7 +299,7 @@ JOIN::prepare(Item ***rref_pointer_array,
|
|||||||
DBUG_RETURN(-1); /* purecov: inspected */
|
DBUG_RETURN(-1); /* purecov: inspected */
|
||||||
|
|
||||||
ref_pointer_array= *rref_pointer_array;
|
ref_pointer_array= *rref_pointer_array;
|
||||||
|
|
||||||
if (having)
|
if (having)
|
||||||
{
|
{
|
||||||
thd->where="having clause";
|
thd->where="having clause";
|
||||||
@ -313,6 +313,7 @@ JOIN::prepare(Item ***rref_pointer_array,
|
|||||||
if (having->with_sum_func)
|
if (having->with_sum_func)
|
||||||
having->split_sum_func(ref_pointer_array, all_fields);
|
having->split_sum_func(ref_pointer_array, all_fields);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
|
if (setup_ftfuncs(select_lex)) /* should be after having->fix_fields */
|
||||||
DBUG_RETURN(-1);
|
DBUG_RETURN(-1);
|
||||||
/*
|
/*
|
||||||
@ -426,7 +427,7 @@ JOIN::optimize()
|
|||||||
|
|
||||||
#ifdef HAVE_REF_TO_FIELDS // Not done yet
|
#ifdef HAVE_REF_TO_FIELDS // Not done yet
|
||||||
/* Add HAVING to WHERE if possible */
|
/* Add HAVING to WHERE if possible */
|
||||||
if (having && !group_list && ! sum_func_count)
|
if (having && !group_list && !sum_func_count)
|
||||||
{
|
{
|
||||||
if (!conds)
|
if (!conds)
|
||||||
{
|
{
|
||||||
|
Reference in New Issue
Block a user