Fixed that NULL and 0 returns 0 instead of NULL
This is coded to not cause a speed impact on top level AND expressions where we don't care if an AND expression returns 0 or NULL mysql-test/r/bdb.result: Fix results after serges last patch mysql-test/r/innodb.result: Fix results after serges last patch mysql-test/r/null.result: Update for new AND handling of NULL scripts/mysqld_safe.sh: Fix 'isroot' test to work even if user is not root sql/item.h: Fixed that NULL and 0 returns 0 instead of NULL sql/item_cmpfunc.cc: Fixed that NULL and 0 returns 0 instead of NULL sql/item_cmpfunc.h: Fixed that NULL and 0 returns 0 instead of NULL sql/sql_base.cc: Fixed that NULL and 0 returns 0 instead of NULL sql/sql_parse.cc: Fixed that NULL and 0 returns 0 instead of NULL sql/sql_select.cc: Fixed that NULL and 0 returns 0 instead of NULL sql/sql_yacc.yy: Fixed that NULL and 0 returns 0 instead of NULL
This commit is contained in:
parent
1b6548d54d
commit
3165440cde
@ -203,7 +203,7 @@ a
|
||||
2
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check error The handler for the table doesn't support check/repair
|
||||
test.t1 check error The handler for the table doesn't support check
|
||||
drop table t1;
|
||||
create table t1 (a int,b varchar(20)) type=bdb;
|
||||
insert into t1 values (1,""), (2,"testing");
|
||||
|
48
mysql-test/r/bool.result
Normal file
48
mysql-test/r/bool.result
Normal file
@ -0,0 +1,48 @@
|
||||
DROP TABLE IF EXISTS t1;
|
||||
SELECT IF(NULL AND 1, 1, 2), IF(1 AND NULL, 1, 2);
|
||||
IF(NULL AND 1, 1, 2) IF(1 AND NULL, 1, 2)
|
||||
2 2
|
||||
SELECT NULL AND 1, 1 AND NULL, 0 AND NULL, NULL and 0;
|
||||
NULL AND 1 1 AND NULL 0 AND NULL NULL and 0
|
||||
NULL NULL 0 0
|
||||
create table t1 (a int);
|
||||
insert into t1 values (0),(1),(NULL);
|
||||
SELECT * FROM t1 WHERE IF(a AND 1, 0, 1);
|
||||
a
|
||||
0
|
||||
NULL
|
||||
SELECT * FROM t1 WHERE IF(1 AND a, 0, 1);
|
||||
a
|
||||
0
|
||||
NULL
|
||||
SELECT * FROM t1 where NOT(a AND 1);
|
||||
a
|
||||
0
|
||||
SELECT * FROM t1 where NOT(1 AND a);
|
||||
a
|
||||
0
|
||||
SELECT * FROM t1 where (a AND 1)=0;
|
||||
a
|
||||
0
|
||||
SELECT * FROM t1 where (1 AND a)=0;
|
||||
a
|
||||
0
|
||||
SELECT * FROM t1 where (1 AND a)=1;
|
||||
a
|
||||
1
|
||||
SELECT * FROM t1 where (1 AND a) IS NULL;
|
||||
a
|
||||
NULL
|
||||
SET @a=0, @b=0;
|
||||
SELECT * FROM t1 WHERE NULL AND (@a:=@a+1);
|
||||
a
|
||||
SELECT * FROM t1 WHERE NOT(a>=0 AND NULL AND (@b:=@b+1));
|
||||
a
|
||||
SELECT * FROM t1 WHERE a=2 OR (NULL AND (@a:=@a+1));
|
||||
a
|
||||
SELECT * FROM t1 WHERE NOT(a=2 OR (NULL AND (@b:=@b+1)));
|
||||
a
|
||||
SELECT @a, @b;
|
||||
@a @b
|
||||
0 6
|
||||
DROP TABLE t1;
|
@ -165,7 +165,7 @@ level id parent_id
|
||||
1 1007 101
|
||||
optimize table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 optimize error The handler for the table doesn't support check/repair
|
||||
test.t1 optimize error The handler for the table doesn't support optimize
|
||||
show keys from t1;
|
||||
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
|
||||
t1 0 PRIMARY 1 id A 87 NULL NULL BTREE
|
||||
@ -189,7 +189,7 @@ create table t1 (a int) type=innodb;
|
||||
insert into t1 values (1), (2);
|
||||
optimize table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 optimize error The handler for the table doesn't support check/repair
|
||||
test.t1 optimize error The handler for the table doesn't support optimize
|
||||
delete from t1 where a = 1;
|
||||
select * from t1;
|
||||
a
|
||||
@ -208,7 +208,7 @@ create index skr on t1 (a);
|
||||
insert into t1 values (3,""), (4,"testing");
|
||||
analyze table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 analyze error The handler for the table doesn't support check/repair
|
||||
test.t1 analyze error The handler for the table doesn't support analyze
|
||||
show keys from t1;
|
||||
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
|
||||
t1 1 skr 1 a A 3 NULL NULL YES BTREE
|
||||
@ -724,7 +724,7 @@ world 2
|
||||
hello 1
|
||||
optimize table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 optimize error The handler for the table doesn't support check/repair
|
||||
test.t1 optimize error The handler for the table doesn't support optimize
|
||||
show keys from t1;
|
||||
Table Non_unique Key_name Seq_in_index Column_name Collation Cardinality Sub_part Packed Null Index_type Comment
|
||||
t1 0 PRIMARY 1 a A 2 NULL NULL BTREE
|
||||
|
@ -30,7 +30,7 @@ SELECT (NULL OR NULL) IS NULL;
|
||||
1
|
||||
select NULL AND 0, 0 and NULL;
|
||||
NULL AND 0 0 and NULL
|
||||
NULL 0
|
||||
0 0
|
||||
select inet_ntoa(null),inet_aton(null),inet_aton("122.256"),inet_aton("122.226."),inet_aton("");
|
||||
inet_ntoa(null) inet_aton(null) inet_aton("122.256") inet_aton("122.226.") inet_aton("")
|
||||
NULL NULL NULL NULL NULL
|
||||
|
28
mysql-test/t/bool.test
Normal file
28
mysql-test/t/bool.test
Normal file
@ -0,0 +1,28 @@
|
||||
#
|
||||
# Test of boolean operations with NULL
|
||||
#
|
||||
|
||||
DROP TABLE IF EXISTS t1;
|
||||
|
||||
SELECT IF(NULL AND 1, 1, 2), IF(1 AND NULL, 1, 2);
|
||||
SELECT NULL AND 1, 1 AND NULL, 0 AND NULL, NULL and 0;
|
||||
|
||||
create table t1 (a int);
|
||||
insert into t1 values (0),(1),(NULL);
|
||||
SELECT * FROM t1 WHERE IF(a AND 1, 0, 1);
|
||||
SELECT * FROM t1 WHERE IF(1 AND a, 0, 1);
|
||||
SELECT * FROM t1 where NOT(a AND 1);
|
||||
SELECT * FROM t1 where NOT(1 AND a);
|
||||
SELECT * FROM t1 where (a AND 1)=0;
|
||||
SELECT * FROM t1 where (1 AND a)=0;
|
||||
SELECT * FROM t1 where (1 AND a)=1;
|
||||
SELECT * FROM t1 where (1 AND a) IS NULL;
|
||||
|
||||
# Verify that NULL optimisation works in AND clause:
|
||||
SET @a=0, @b=0;
|
||||
SELECT * FROM t1 WHERE NULL AND (@a:=@a+1);
|
||||
SELECT * FROM t1 WHERE NOT(a>=0 AND NULL AND (@b:=@b+1));
|
||||
SELECT * FROM t1 WHERE a=2 OR (NULL AND (@a:=@a+1));
|
||||
SELECT * FROM t1 WHERE NOT(a=2 OR (NULL AND (@b:=@b+1)));
|
||||
SELECT @a, @b;
|
||||
DROP TABLE t1;
|
@ -204,7 +204,7 @@ else
|
||||
fi
|
||||
|
||||
USER_OPTION=""
|
||||
if test "x$USER" = "xroot"
|
||||
if test -w / -o "$USER" = "root"
|
||||
then
|
||||
if test "$user" != "root" -o $SET_USER = 1
|
||||
then
|
||||
|
@ -85,6 +85,7 @@ public:
|
||||
virtual bool get_time(TIME *ltime);
|
||||
virtual bool is_null() { return 0; }
|
||||
virtual unsigned int size_of()= 0;
|
||||
virtual void top_level_item() {}
|
||||
};
|
||||
|
||||
|
||||
|
@ -26,8 +26,8 @@
|
||||
|
||||
/*
|
||||
Test functions
|
||||
These returns 0LL if false and 1LL if true and null if some arg is null
|
||||
'AND' and 'OR' never return null
|
||||
Most of these returns 0LL if false and 1LL if true and
|
||||
NULL if some arg is NULL.
|
||||
*/
|
||||
|
||||
longlong Item_func_not::val_int()
|
||||
@ -533,6 +533,7 @@ Item_func_if::fix_length_and_dec()
|
||||
else
|
||||
cached_result_type=arg1_type; // Should be INT_RESULT
|
||||
}
|
||||
args[0]->top_level_item();
|
||||
}
|
||||
|
||||
|
||||
@ -1128,6 +1129,8 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables)
|
||||
const_item_cache&=item->const_item();
|
||||
if (item->maybe_null)
|
||||
maybe_null=1;
|
||||
if (abort_on_null)
|
||||
item->top_level_item();
|
||||
}
|
||||
if (thd)
|
||||
thd->cond_count+=list.elements;
|
||||
@ -1196,28 +1199,41 @@ void Item_cond::print(String *str)
|
||||
str->append(')');
|
||||
}
|
||||
|
||||
/*
|
||||
Evalution of AND(expr, expr, expr ...)
|
||||
|
||||
NOTES:
|
||||
abort_if_null is set for AND expressions for which we don't care if the
|
||||
result is NULL or 0. This is set for:
|
||||
- WHERE clause
|
||||
- HAVING clause
|
||||
- IF(expression)
|
||||
|
||||
RETURN VALUES
|
||||
1 If all expressions are true
|
||||
0 If all expressions are false or if we find a NULL expression and
|
||||
'abort_on_null' is set.
|
||||
NULL if all expression are either 1 or NULL
|
||||
*/
|
||||
|
||||
|
||||
longlong Item_cond_and::val_int()
|
||||
{
|
||||
List_iterator_fast<Item> li(list);
|
||||
Item *item;
|
||||
null_value= 0;
|
||||
while ((item=li++))
|
||||
{
|
||||
if (item->val_int() == 0)
|
||||
{
|
||||
/*
|
||||
TODO: In case of NULL, ANSI would require us to continue evaluation
|
||||
until we get a FALSE value or run out of values; This would
|
||||
require a lot of unnecessary evaluation, which we skip for now
|
||||
*/
|
||||
null_value=item->null_value;
|
||||
return 0;
|
||||
if (abort_on_null || !(null_value= item->null_value))
|
||||
return 0; // return FALSE
|
||||
}
|
||||
}
|
||||
null_value=0;
|
||||
return 1;
|
||||
return null_value ? 0 : 1;
|
||||
}
|
||||
|
||||
|
||||
longlong Item_cond_or::val_int()
|
||||
{
|
||||
List_iterator_fast<Item> li(list);
|
||||
@ -1260,15 +1276,15 @@ longlong Item_cond_or::val_int()
|
||||
Item *and_expressions(Item *a, Item *b, Item **org_item)
|
||||
{
|
||||
if (!a)
|
||||
return (*org_item= (Item*) b);
|
||||
return (*org_item= b);
|
||||
if (a == *org_item)
|
||||
{
|
||||
Item_cond *res;
|
||||
if ((res= new Item_cond_and(a, (Item*) b)))
|
||||
if ((res= new Item_cond_and(a, b)))
|
||||
res->used_tables_cache= a->used_tables() | b->used_tables();
|
||||
return res;
|
||||
}
|
||||
if (((Item_cond_and*) a)->add((Item*) b))
|
||||
if (((Item_cond_and*) a)->add(b))
|
||||
return 0;
|
||||
((Item_cond_and*) a)->used_tables_cache|= b->used_tables();
|
||||
return a;
|
||||
|
@ -560,10 +560,12 @@ class Item_cond :public Item_bool_func
|
||||
{
|
||||
protected:
|
||||
List<Item> list;
|
||||
bool abort_on_null;
|
||||
public:
|
||||
Item_cond() : Item_bool_func() { const_item_cache=0; }
|
||||
Item_cond(Item *i1,Item *i2) :Item_bool_func()
|
||||
{ list.push_back(i1); list.push_back(i2); }
|
||||
/* Item_cond() is only used to create top level items */
|
||||
Item_cond() : Item_bool_func(), abort_on_null(1) { const_item_cache=0; }
|
||||
Item_cond(Item *i1,Item *i2) :Item_bool_func(), abort_on_null(0)
|
||||
{ list.push_back(i1); list.push_back(i2); }
|
||||
~Item_cond() { list.delete_elements(); }
|
||||
bool add(Item *item) { return list.push_back(item); }
|
||||
bool fix_fields(THD *,struct st_table_list *);
|
||||
@ -576,6 +578,7 @@ public:
|
||||
void split_sum_func(List<Item> &fields);
|
||||
friend int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds);
|
||||
unsigned int size_of() { return sizeof(*this);}
|
||||
void top_level_item() { abort_on_null=1; }
|
||||
};
|
||||
|
||||
|
||||
|
@ -1976,6 +1976,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
|
||||
Item_cond_and *cond_and=new Item_cond_and();
|
||||
if (!cond_and) // If not out of memory
|
||||
DBUG_RETURN(1);
|
||||
cond_and->top_level_item();
|
||||
|
||||
uint i,j;
|
||||
for (i=0 ; i < t1->fields ; i++)
|
||||
|
@ -3324,12 +3324,16 @@ static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result)
|
||||
|
||||
void add_join_on(TABLE_LIST *b,Item *expr)
|
||||
{
|
||||
if (!b->on_expr)
|
||||
b->on_expr=expr;
|
||||
else
|
||||
if (expr)
|
||||
{
|
||||
// This only happens if you have both a right and left join
|
||||
b->on_expr=new Item_cond_and(b->on_expr,expr);
|
||||
if (!b->on_expr)
|
||||
b->on_expr=expr;
|
||||
else
|
||||
{
|
||||
// This only happens if you have both a right and left join
|
||||
b->on_expr=new Item_cond_and(b->on_expr,expr);
|
||||
}
|
||||
b->on_expr->top_level_item();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -360,6 +360,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
{
|
||||
conds->fix_fields(thd,tables);
|
||||
conds->change_ref_to_fields(thd,tables);
|
||||
conds->top_level_item();
|
||||
having=0;
|
||||
}
|
||||
}
|
||||
@ -869,6 +870,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds,
|
||||
sort_table_cond)))
|
||||
goto err;
|
||||
table->select_cond=table->select->cond;
|
||||
table->select_cond->top_level_item();
|
||||
DBUG_EXECUTE("where",print_where(table->select->cond,
|
||||
"select and having"););
|
||||
having=make_cond_for_table(having,~ (table_map) 0,~used_tables);
|
||||
@ -5490,6 +5492,7 @@ make_cond_for_table(COND *cond,table_map tables,table_map used_table)
|
||||
{
|
||||
if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC)
|
||||
{
|
||||
/* Create new top level AND item */
|
||||
Item_cond_and *new_cond=new Item_cond_and;
|
||||
if (!new_cond)
|
||||
DBUG_RETURN((COND*) 0); // OOM /* purecov: inspected */
|
||||
@ -5527,6 +5530,7 @@ make_cond_for_table(COND *cond,table_map tables,table_map used_table)
|
||||
new_cond->argument_list()->push_back(fix);
|
||||
}
|
||||
new_cond->used_tables_cache=((Item_cond_or*) cond)->used_tables_cache;
|
||||
new_cond->top_level_item();
|
||||
DBUG_RETURN(new_cond);
|
||||
}
|
||||
}
|
||||
@ -5886,6 +5890,7 @@ static bool fix_having(JOIN *join, Item **having)
|
||||
sort_table_cond)))
|
||||
DBUG_RETURN(1);
|
||||
table->select_cond=table->select->cond;
|
||||
table->select_cond->top_level_item();
|
||||
DBUG_EXECUTE("where",print_where(table->select_cond,
|
||||
"select and having"););
|
||||
*having=make_cond_for_table(*having,~ (table_map) 0,~used_tables);
|
||||
|
@ -2178,15 +2178,25 @@ opt_table_alias:
|
||||
|
||||
where_clause:
|
||||
/* empty */ { Select->where= 0; }
|
||||
| WHERE expr { Select->where= $2; };
|
||||
| WHERE expr
|
||||
{
|
||||
Select->where= $2;
|
||||
if ($2)
|
||||
$2->top_level_item();
|
||||
}
|
||||
;
|
||||
|
||||
having_clause:
|
||||
/* empty */
|
||||
| HAVING { Select->create_refs=1; } expr
|
||||
{
|
||||
SELECT_LEX *sel=Select;
|
||||
sel->having= $3; sel->create_refs=0;
|
||||
};
|
||||
sel->having= $3;
|
||||
sel->create_refs=0;
|
||||
if ($3)
|
||||
$3->top_level_item();
|
||||
}
|
||||
;
|
||||
|
||||
opt_escape:
|
||||
ESCAPE_SYM TEXT_STRING { $$= $2.str; }
|
||||
|
Loading…
x
Reference in New Issue
Block a user