Commit 876f3f4d authored by monty@mashka.mysql.fi's avatar monty@mashka.mysql.fi

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
parent b0f5c6d6
......@@ -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");
......
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
......
#
# 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 @@ class Item {
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,9 +560,11 @@ 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()
/* 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); }
......@@ -576,6 +578,7 @@ class Item_cond :public Item_bool_func
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,6 +3324,8 @@ static bool create_total_list(THD *thd, LEX *lex, TABLE_LIST **result)
void add_join_on(TABLE_LIST *b,Item *expr)
{
if (expr)
{
if (!b->on_expr)
b->on_expr=expr;
else
......@@ -3331,6 +3333,8 @@ void add_join_on(TABLE_LIST *b,Item *expr)
// 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; }
......
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