mirror of
https://github.com/MariaDB/server.git
synced 2025-10-12 12:25:37 +03:00
MDEV-4836: Merge into 5.5-main
This commit is contained in:
@@ -2139,6 +2139,38 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 Using index
|
||||
drop table t0, t1;
|
||||
#
|
||||
# MDEV-4836: Wrong result on <not null date column> IS NULL (old documented hack stopped working)
|
||||
# (this is a regression after fix for MDEV-4817)
|
||||
#
|
||||
CREATE TABLE t1 (id INT, d DATE NOT NULL);
|
||||
INSERT INTO t1 VALUES (1,'0000-00-00'),(2,'0000-00-00');
|
||||
CREATE TABLE t2 (i INT);
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (id=i) WHERE NULL OR d IS NULL;
|
||||
id d i
|
||||
1 0000-00-00 NULL
|
||||
2 0000-00-00 NULL
|
||||
DROP TABLE t1,t2;
|
||||
CREATE TABLE t1 (i1 INT, d1 DATE NOT NULL);
|
||||
INSERT INTO t1 VALUES (1,'2012-12-21'),(2,'0000-00-00');
|
||||
CREATE TABLE t2 (i2 INT, j2 INT);
|
||||
INSERT INTO t2 VALUES (1,10),(2,20);
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON i1 = j2 WHERE d1 IS NULL AND 1 OR i1 = i2;
|
||||
i1 d1 i2 j2
|
||||
2 0000-00-00 NULL NULL
|
||||
DROP TABLE t1,t2;
|
||||
# Another testcase
|
||||
CREATE TABLE t1 (i1 INT) ENGINE=MyISAM;
|
||||
INSERT INTO t1 VALUES (NULL);
|
||||
CREATE TABLE t2 (i2 INT, a INT, b INT) ENGINE=MyISAM;
|
||||
CREATE ALGORITHM=TEMPTABLE VIEW v2 AS SELECT * FROM t2;
|
||||
INSERT INTO t2 VALUES (NULL,1,2),(NULL,2,3);
|
||||
SELECT * FROM t1 LEFT JOIN v2 ON i1 = i2 WHERE a < b;
|
||||
i1 i2 a b
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON i1 = i2 WHERE a < b;
|
||||
i1 i2 a b
|
||||
drop view v2;
|
||||
drop table t1,t2;
|
||||
#
|
||||
# Bug mdev-4942: LEFT JOIN with conjunctive
|
||||
# <non-nullable datetime field> IS NULL in WHERE
|
||||
# causes an assert failure
|
||||
|
@@ -2150,6 +2150,38 @@ id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 eq_ref PRIMARY PRIMARY 4 test.t0.a 1 Using index
|
||||
drop table t0, t1;
|
||||
#
|
||||
# MDEV-4836: Wrong result on <not null date column> IS NULL (old documented hack stopped working)
|
||||
# (this is a regression after fix for MDEV-4817)
|
||||
#
|
||||
CREATE TABLE t1 (id INT, d DATE NOT NULL);
|
||||
INSERT INTO t1 VALUES (1,'0000-00-00'),(2,'0000-00-00');
|
||||
CREATE TABLE t2 (i INT);
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (id=i) WHERE NULL OR d IS NULL;
|
||||
id d i
|
||||
1 0000-00-00 NULL
|
||||
2 0000-00-00 NULL
|
||||
DROP TABLE t1,t2;
|
||||
CREATE TABLE t1 (i1 INT, d1 DATE NOT NULL);
|
||||
INSERT INTO t1 VALUES (1,'2012-12-21'),(2,'0000-00-00');
|
||||
CREATE TABLE t2 (i2 INT, j2 INT);
|
||||
INSERT INTO t2 VALUES (1,10),(2,20);
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON i1 = j2 WHERE d1 IS NULL AND 1 OR i1 = i2;
|
||||
i1 d1 i2 j2
|
||||
2 0000-00-00 NULL NULL
|
||||
DROP TABLE t1,t2;
|
||||
# Another testcase
|
||||
CREATE TABLE t1 (i1 INT) ENGINE=MyISAM;
|
||||
INSERT INTO t1 VALUES (NULL);
|
||||
CREATE TABLE t2 (i2 INT, a INT, b INT) ENGINE=MyISAM;
|
||||
CREATE ALGORITHM=TEMPTABLE VIEW v2 AS SELECT * FROM t2;
|
||||
INSERT INTO t2 VALUES (NULL,1,2),(NULL,2,3);
|
||||
SELECT * FROM t1 LEFT JOIN v2 ON i1 = i2 WHERE a < b;
|
||||
i1 i2 a b
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON i1 = i2 WHERE a < b;
|
||||
i1 i2 a b
|
||||
drop view v2;
|
||||
drop table t1,t2;
|
||||
#
|
||||
# Bug mdev-4942: LEFT JOIN with conjunctive
|
||||
# <non-nullable datetime field> IS NULL in WHERE
|
||||
# causes an assert failure
|
||||
|
@@ -1686,6 +1686,39 @@ explain select * from t1 left join t0 on t0.a=t1.pk where t0.person_id='fooo' or
|
||||
|
||||
drop table t0, t1;
|
||||
|
||||
--echo #
|
||||
--echo # MDEV-4836: Wrong result on <not null date column> IS NULL (old documented hack stopped working)
|
||||
--echo # (this is a regression after fix for MDEV-4817)
|
||||
--echo #
|
||||
CREATE TABLE t1 (id INT, d DATE NOT NULL);
|
||||
INSERT INTO t1 VALUES (1,'0000-00-00'),(2,'0000-00-00');
|
||||
CREATE TABLE t2 (i INT);
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON (id=i) WHERE NULL OR d IS NULL;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
|
||||
CREATE TABLE t1 (i1 INT, d1 DATE NOT NULL);
|
||||
INSERT INTO t1 VALUES (1,'2012-12-21'),(2,'0000-00-00');
|
||||
|
||||
CREATE TABLE t2 (i2 INT, j2 INT);
|
||||
INSERT INTO t2 VALUES (1,10),(2,20);
|
||||
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON i1 = j2 WHERE d1 IS NULL AND 1 OR i1 = i2;
|
||||
DROP TABLE t1,t2;
|
||||
|
||||
--echo # Another testcase
|
||||
CREATE TABLE t1 (i1 INT) ENGINE=MyISAM;
|
||||
INSERT INTO t1 VALUES (NULL);
|
||||
|
||||
CREATE TABLE t2 (i2 INT, a INT, b INT) ENGINE=MyISAM;
|
||||
CREATE ALGORITHM=TEMPTABLE VIEW v2 AS SELECT * FROM t2;
|
||||
|
||||
INSERT INTO t2 VALUES (NULL,1,2),(NULL,2,3);
|
||||
SELECT * FROM t1 LEFT JOIN v2 ON i1 = i2 WHERE a < b;
|
||||
SELECT * FROM t1 LEFT JOIN t2 ON i1 = i2 WHERE a < b;
|
||||
|
||||
drop view v2;
|
||||
drop table t1,t2;
|
||||
|
||||
--echo #
|
||||
--echo # Bug mdev-4942: LEFT JOIN with conjunctive
|
||||
|
@@ -4302,7 +4302,8 @@ Item_cond::fix_fields(THD *thd, Item **ref)
|
||||
used_tables_cache|= item->used_tables();
|
||||
if (item->const_item())
|
||||
{
|
||||
if (!item->is_expensive() && item->val_int() == 0)
|
||||
if (!item->is_expensive() && !cond_has_datetime_is_null(item) &&
|
||||
item->val_int() == 0)
|
||||
{
|
||||
/*
|
||||
This is "... OR false_cond OR ..."
|
||||
@@ -4314,27 +4315,18 @@ Item_cond::fix_fields(THD *thd, Item **ref)
|
||||
/*
|
||||
This is "... OR const_cond OR ..."
|
||||
In this case, cond_or->not_null_tables()=0, because the condition
|
||||
some_cond_or might be true regardless of what tables are
|
||||
NULL-complemented.
|
||||
const_cond might evaluate to true (regardless of whether some tables
|
||||
were NULL-complemented).
|
||||
*/
|
||||
and_tables_cache= (table_map) 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
If an item is a
|
||||
- constant
|
||||
- inexpensive
|
||||
- its value is 0
|
||||
then we don't need to account it in not_null_tables_cache
|
||||
*/
|
||||
//if (!(item->const_item() && !item->is_expensive() ))
|
||||
{
|
||||
table_map tmp_table_map= item->not_null_tables();
|
||||
not_null_tables_cache|= tmp_table_map;
|
||||
and_tables_cache&= tmp_table_map;
|
||||
}
|
||||
table_map tmp_table_map= item->not_null_tables();
|
||||
not_null_tables_cache|= tmp_table_map;
|
||||
and_tables_cache&= tmp_table_map;
|
||||
|
||||
const_item_cache= FALSE;
|
||||
}
|
||||
|
||||
@@ -4363,7 +4355,8 @@ Item_cond::eval_not_null_tables(uchar *opt_arg)
|
||||
table_map tmp_table_map;
|
||||
if (item->const_item())
|
||||
{
|
||||
if (!item->is_expensive() && item->val_int() == 0)
|
||||
if (!item->is_expensive() && !cond_has_datetime_is_null(item) &&
|
||||
item->val_int() == 0)
|
||||
{
|
||||
/*
|
||||
This is "... OR false_cond OR ..."
|
||||
|
@@ -13536,6 +13536,57 @@ void propagate_new_equalities(THD *thd, Item *cond,
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Check if cond_is_datetime_is_null() is true for the condition cond, or
|
||||
for any of its AND/OR-children
|
||||
*/
|
||||
bool cond_has_datetime_is_null(Item *cond)
|
||||
{
|
||||
if (cond_is_datetime_is_null(cond))
|
||||
return true;
|
||||
|
||||
if (cond->type() == Item::COND_ITEM)
|
||||
{
|
||||
List<Item> *cond_arg_list= ((Item_cond*) cond)->argument_list();
|
||||
List_iterator<Item> li(*cond_arg_list);
|
||||
Item *item;
|
||||
while ((item= li++))
|
||||
{
|
||||
if (cond_has_datetime_is_null(item))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
Check if passed condtition has for of
|
||||
|
||||
not_null_date_col IS NULL
|
||||
|
||||
where not_null_date_col has a datte or datetime type
|
||||
*/
|
||||
|
||||
bool cond_is_datetime_is_null(Item *cond)
|
||||
{
|
||||
if (cond->type() == Item::FUNC_ITEM &&
|
||||
((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
|
||||
{
|
||||
Item **args= ((Item_func_isnull*) cond)->arguments();
|
||||
if (args[0]->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
Field *field=((Item_field*) args[0])->field;
|
||||
|
||||
if (((field->type() == MYSQL_TYPE_DATE) ||
|
||||
(field->type() == MYSQL_TYPE_DATETIME)) &&
|
||||
(field->flags & NOT_NULL_FLAG))
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -13804,53 +13855,45 @@ internal_remove_eq_conds(THD *thd, COND *cond, Item::cond_result *cond_value)
|
||||
return item;
|
||||
}
|
||||
}
|
||||
else if (cond->type() == Item::FUNC_ITEM &&
|
||||
((Item_func*) cond)->functype() == Item_func::ISNULL_FUNC)
|
||||
else if (cond_is_datetime_is_null(cond))
|
||||
{
|
||||
Item_func_isnull *func=(Item_func_isnull*) cond;
|
||||
Item **args= func->arguments();
|
||||
if (args[0]->type() == Item::FIELD_ITEM)
|
||||
{
|
||||
Field *field=((Item_field*) args[0])->field;
|
||||
/* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */
|
||||
/*
|
||||
See BUG#12594011
|
||||
Documentation says that
|
||||
SELECT datetime_notnull d FROM t1 WHERE d IS NULL
|
||||
shall return rows where d=='0000-00-00'
|
||||
/* fix to replace 'NULL' dates with '0' (shreeve@uci.edu) */
|
||||
/*
|
||||
See BUG#12594011
|
||||
Documentation says that
|
||||
SELECT datetime_notnull d FROM t1 WHERE d IS NULL
|
||||
shall return rows where d=='0000-00-00'
|
||||
|
||||
Thus, for DATE and DATETIME columns defined as NOT NULL,
|
||||
"date_notnull IS NULL" has to be modified to
|
||||
"date_notnull IS NULL OR date_notnull == 0" (if outer join)
|
||||
"date_notnull == 0" (otherwise)
|
||||
Thus, for DATE and DATETIME columns defined as NOT NULL,
|
||||
"date_notnull IS NULL" has to be modified to
|
||||
"date_notnull IS NULL OR date_notnull == 0" (if outer join)
|
||||
"date_notnull == 0" (otherwise)
|
||||
|
||||
*/
|
||||
if (((field->type() == MYSQL_TYPE_DATE) ||
|
||||
(field->type() == MYSQL_TYPE_DATETIME)) &&
|
||||
(field->flags & NOT_NULL_FLAG))
|
||||
{
|
||||
Item *item0= new(thd->mem_root) Item_int((longlong)0, 1);
|
||||
Item *eq_cond= new(thd->mem_root) Item_func_eq(args[0], item0);
|
||||
if (!eq_cond)
|
||||
return cond;
|
||||
*/
|
||||
Item **args= ((Item_func_isnull*) cond)->arguments();
|
||||
Field *field=((Item_field*) args[0])->field;
|
||||
|
||||
Item *item0= new(thd->mem_root) Item_int((longlong)0, 1);
|
||||
Item *eq_cond= new(thd->mem_root) Item_func_eq(args[0], item0);
|
||||
if (!eq_cond)
|
||||
return cond;
|
||||
|
||||
if (field->table->pos_in_table_list->is_inner_table_of_outer_join())
|
||||
{
|
||||
// outer join: transform "col IS NULL" to "col IS NULL or col=0"
|
||||
Item *or_cond= new(thd->mem_root) Item_cond_or(eq_cond, cond);
|
||||
if (!or_cond)
|
||||
return cond;
|
||||
cond= or_cond;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not outer join: transform "col IS NULL" to "col=0"
|
||||
cond= eq_cond;
|
||||
}
|
||||
|
||||
cond->fix_fields(thd, &cond);
|
||||
}
|
||||
{
|
||||
// outer join: transform "col IS NULL" to "col IS NULL or col=0"
|
||||
Item *or_cond= new(thd->mem_root) Item_cond_or(eq_cond, cond);
|
||||
if (!or_cond)
|
||||
return cond;
|
||||
cond= or_cond;
|
||||
}
|
||||
else
|
||||
{
|
||||
// not outer join: transform "col IS NULL" to "col=0"
|
||||
cond= eq_cond;
|
||||
}
|
||||
|
||||
cond->fix_fields(thd, &cond);
|
||||
|
||||
if (cond->const_item() && !cond->is_expensive())
|
||||
{
|
||||
*cond_value= eval_const_cond(cond) ? Item::COND_TRUE : Item::COND_FALSE;
|
||||
|
@@ -1800,6 +1800,8 @@ ORDER *simple_remove_const(ORDER *order, COND *where);
|
||||
bool const_expression_in_where(COND *cond, Item *comp_item,
|
||||
Field *comp_field= NULL,
|
||||
Item **const_item= NULL);
|
||||
bool cond_is_datetime_is_null(Item *cond);
|
||||
bool cond_has_datetime_is_null(Item *cond);
|
||||
|
||||
/* Table elimination entry point function */
|
||||
void eliminate_tables(JOIN *join);
|
||||
|
Reference in New Issue
Block a user