diff options
-rw-r--r-- | mysql-test/r/bdb.result | 2 | ||||
-rw-r--r-- | mysql-test/r/bool.result | 48 | ||||
-rw-r--r-- | mysql-test/r/innodb.result | 8 | ||||
-rw-r--r-- | mysql-test/r/null.result | 2 | ||||
-rw-r--r-- | mysql-test/t/bool.test | 28 | ||||
-rw-r--r-- | scripts/mysqld_safe.sh | 2 | ||||
-rw-r--r-- | sql/item.h | 1 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 44 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 9 | ||||
-rw-r--r-- | sql/sql_base.cc | 1 | ||||
-rw-r--r-- | sql/sql_parse.cc | 14 | ||||
-rw-r--r-- | sql/sql_select.cc | 5 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 16 |
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; } |