summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/bdb.result2
-rw-r--r--mysql-test/r/bool.result48
-rw-r--r--mysql-test/r/innodb.result8
-rw-r--r--mysql-test/r/null.result2
-rw-r--r--mysql-test/t/bool.test28
-rw-r--r--scripts/mysqld_safe.sh2
-rw-r--r--sql/item.h1
-rw-r--r--sql/item_cmpfunc.cc44
-rw-r--r--sql/item_cmpfunc.h9
-rw-r--r--sql/sql_base.cc1
-rw-r--r--sql/sql_parse.cc14
-rw-r--r--sql/sql_select.cc5
-rw-r--r--sql/sql_yacc.yy16
13 files changed, 148 insertions, 32 deletions
diff --git a/mysql-test/r/bdb.result b/mysql-test/r/bdb.result
index e52878b9759..a815f2f8fab 100644
--- a/mysql-test/r/bdb.result
+++ b/mysql-test/r/bdb.result
@@ -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");
diff --git a/mysql-test/r/bool.result b/mysql-test/r/bool.result
new file mode 100644
index 00000000000..dc170ee5150
--- /dev/null
+++ b/mysql-test/r/bool.result
@@ -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;
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index 62f5734a217..67c78f34392 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -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
diff --git a/mysql-test/r/null.result b/mysql-test/r/null.result
index e6e3b7155a3..07724a56025 100644
--- a/mysql-test/r/null.result
+++ b/mysql-test/r/null.result
@@ -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
diff --git a/mysql-test/t/bool.test b/mysql-test/t/bool.test
new file mode 100644
index 00000000000..5754acf4bcd
--- /dev/null
+++ b/mysql-test/t/bool.test
@@ -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;
diff --git a/scripts/mysqld_safe.sh b/scripts/mysqld_safe.sh
index 2cc11bb0979..96d3437f96d 100644
--- a/scripts/mysqld_safe.sh
+++ b/scripts/mysqld_safe.sh
@@ -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
diff --git a/sql/item.h b/sql/item.h
index 246e1fbcbd6..563db2291fb 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -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() {}
};
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index 3cd55934950..93e24525d06 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -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;
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index 83035720df6..f2c0ee403d2 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -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; }
};
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index cf41d851137..42d35c05f23 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -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++)
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 086a0a561a0..eb2d2ace467 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -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();
}
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 25587f0ada7..561549ee843 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -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);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 911fc12d9c4..93532d013b5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -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; }