diff options
-rw-r--r-- | mysql-test/r/bool.result | 48 | ||||
-rw-r--r-- | mysql-test/r/func_time.result | 6 | ||||
-rw-r--r-- | mysql-test/r/null.result | 2 | ||||
-rw-r--r-- | mysql-test/t/bool.test | 28 | ||||
-rw-r--r-- | mysql-test/t/func_time.test | 3 | ||||
-rw-r--r-- | scripts/mysqld_safe.sh | 2 | ||||
-rw-r--r-- | sql/item.h | 1 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 43 | ||||
-rw-r--r-- | sql/item_cmpfunc.h | 14 | ||||
-rw-r--r-- | sql/item_timefunc.cc | 19 | ||||
-rw-r--r-- | sql/mysqld.cc | 8 | ||||
-rw-r--r-- | sql/sql_base.cc | 5 | ||||
-rw-r--r-- | sql/sql_parse.cc | 14 | ||||
-rw-r--r-- | sql/sql_select.cc | 7 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 16 | ||||
-rw-r--r-- | tests/Makefile.am | 2 |
16 files changed, 183 insertions, 35 deletions
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/func_time.result b/mysql-test/r/func_time.result index e4fd25a34f0..4a1012f73bf 100644 --- a/mysql-test/r/func_time.result +++ b/mysql-test/r/func_time.result @@ -84,6 +84,12 @@ select yearweek("2000-01-01",1) as '2000', yearweek("2001-01-01",1) as '2001', y select yearweek("2000-01-06",1) as '2000', yearweek("2001-01-06",1) as '2001', yearweek("2002-01-06",1) as '2002',yearweek("2003-01-06",1) as '2003', yearweek("2004-01-06",1) as '2004', yearweek("2005-01-06",1) as '2005', yearweek("2006-01-06",1) as '2006'; 2000 2001 2002 2003 2004 2005 2006 200001 200101 200201 200302 200402 200501 200601 +select week(19981231,2), week(19981231,3), week(20000101,2), week(20000101,3); +week(19981231,2) week(19981231,3) week(20000101,2) week(20000101,3) +52 53 52 52 +select week(20001231,2),week(20001231,3); +week(20001231,2) week(20001231,3) +1 52 select date_format('1998-12-31','%x-%v'),date_format('1999-01-01','%x-%v'); date_format('1998-12-31','%x-%v') date_format('1999-01-01','%x-%v') 1998-53 1998-53 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/mysql-test/t/func_time.test b/mysql-test/t/func_time.test index 7d5ab73fa4c..2ff57959965 100644 --- a/mysql-test/t/func_time.test +++ b/mysql-test/t/func_time.test @@ -34,6 +34,9 @@ select yearweek("2000-01-01",0) as '2000', yearweek("2001-01-01",0) as '2001', y select yearweek("2000-01-06",0) as '2000', yearweek("2001-01-06",0) as '2001', yearweek("2002-01-06",0) as '2002',yearweek("2003-01-06",0) as '2003', yearweek("2004-01-06",0) as '2004', yearweek("2005-01-06",0) as '2005', yearweek("2006-01-06",0) as '2006'; select yearweek("2000-01-01",1) as '2000', yearweek("2001-01-01",1) as '2001', yearweek("2002-01-01",1) as '2002',yearweek("2003-01-01",1) as '2003', yearweek("2004-01-01",1) as '2004', yearweek("2005-01-01",1) as '2005', yearweek("2006-01-01",1) as '2006'; select yearweek("2000-01-06",1) as '2000', yearweek("2001-01-06",1) as '2001', yearweek("2002-01-06",1) as '2002',yearweek("2003-01-06",1) as '2003', yearweek("2004-01-06",1) as '2004', yearweek("2005-01-06",1) as '2005', yearweek("2006-01-06",1) as '2006'; +select week(19981231,2), week(19981231,3), week(20000101,2), week(20000101,3); +select week(20001231,2),week(20001231,3); + select date_format('1998-12-31','%x-%v'),date_format('1999-01-01','%x-%v'); select date_format('1999-12-31','%x-%v'),date_format('2000-01-01','%x-%v'); 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..ee587289168 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() @@ -1121,6 +1121,8 @@ Item_cond::fix_fields(THD *thd,TABLE_LIST *tables) #endif item= *li.ref(); // new current item } + if (abort_on_null) + item->top_level_item(); if (item->fix_fields(thd,tables)) return 1; /* purecov: inspected */ used_tables_cache|=item->used_tables(); @@ -1196,28 +1198,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 +1275,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..e163bc40a6e 100644 --- a/sql/item_cmpfunc.h +++ b/sql/item_cmpfunc.h @@ -216,6 +216,11 @@ public: longlong val_int(); String *val_str(String *str); enum Item_result result_type () const { return cached_result_type; } + bool fix_fields(THD *thd,struct st_table_list *tlist) + { + args[0]->top_level_item(); + return Item_func::fix_fields(thd,tlist); + } void fix_length_and_dec(); const char *func_name() const { return "if"; } unsigned int size_of() { return sizeof(*this);} @@ -560,10 +565,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 +583,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/item_timefunc.cc b/sql/item_timefunc.cc index 1e222fddcfc..558dd807d80 100644 --- a/sql/item_timefunc.cc +++ b/sql/item_timefunc.cc @@ -175,15 +175,28 @@ longlong Item_func_second::val_int() } -// Returns the week of year in the range of 0 - 53 +/* + Returns the week of year. + + The bits in week_format has the following meaning: + 0 If not set: USA format: Sunday is first day of week + If set: ISO format: Monday is first day of week + 1 If not set: Week is in range 0-53 + If set Week is in range 1-53. +*/ longlong Item_func_week::val_int() { uint year; + uint week_format; TIME ltime; if (get_arg0_date(<ime,0)) return 0; - return (longlong) calc_week(<ime, 0, args[1]->val_int() == 0, &year); + week_format= args[1]->val_int(); + return (longlong) calc_week(<ime, + (week_format & 2) != 0, + (week_format & 1) == 0, + &year); } @@ -193,7 +206,7 @@ longlong Item_func_yearweek::val_int() TIME ltime; if (get_arg0_date(<ime,0)) return 0; - week=calc_week(<ime, 1, args[1]->val_int() == 0, &year); + week=calc_week(<ime, 1, (args[1]->val_int() & 1) == 0, &year); return week+year*100; } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 48c7cbe3ba3..62f8ed62877 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -2003,6 +2003,8 @@ int main(int argc, char **argv) if (ha_init()) { sql_print_error("Can't init databases"); + if (unix_sock != INVALID_SOCKET) + unlink(mysql_unix_port); exit(1); } ha_key_cache(); @@ -2038,6 +2040,8 @@ int main(int argc, char **argv) pthread_key_create(&THR_MALLOC,NULL)) { sql_print_error("Can't create thread-keys"); + if (unix_sock != INVALID_SOCKET) + unlink(mysql_unix_port); exit(1); } start_signal_handler(); // Creates pidfile @@ -2050,6 +2054,8 @@ int main(int argc, char **argv) if (!opt_bootstrap) (void) my_delete(pidfile_name,MYF(MY_WME)); // Not needed anymore #endif + if (unix_sock != INVALID_SOCKET) + unlink(mysql_unix_port); exit(1); } if (!opt_noacl) @@ -4467,8 +4473,8 @@ fn_format_relative_to_data_home(my_string to, const char *name, static void fix_paths(void) { char buff[FN_REFLEN]; - (void) fn_format(mysql_home,mysql_home,"","",16); // Remove symlinks convert_dirname(mysql_home,mysql_home,NullS); + my_realpath(mysql_home,mysql_home,MYF(0)); convert_dirname(mysql_real_data_home,mysql_real_data_home,NullS); convert_dirname(language,language,NullS); (void) my_load_path(mysql_home,mysql_home,""); // Resolve current dir diff --git a/sql/sql_base.cc b/sql/sql_base.cc index cf41d851137..23ba04bd6ed 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -376,14 +376,14 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, if (!found) if_wait_for_refresh=0; // Nothing to wait for } + if (!tables) + kill_delayed_threads(); if (if_wait_for_refresh) { /* If there is any table that has a lower refresh_version, wait until this is closed (or this thread is killed) before returning */ - if (!tables) - kill_delayed_threads(); thd->mysys_var->current_mutex= &LOCK_open; thd->mysys_var->current_cond= &COND_refresh; thd->proc_info="Flushing tables"; @@ -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 cb2e73c0c26..69dcab61ad7 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -359,6 +359,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; } } @@ -868,6 +869,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); @@ -5384,6 +5386,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) return (COND*) 0; // OOM /* purecov: inspected */ @@ -5421,7 +5424,8 @@ 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; - return new_cond; + new_cond->top_level_item(); + DBUG_RETURN(new_cond); } } @@ -5772,6 +5776,7 @@ static bool fix_having(JOIN *join, Item **having) sort_table_cond))) 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; } diff --git a/tests/Makefile.am b/tests/Makefile.am index cdb623fa2a0..356da61ed57 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -24,7 +24,7 @@ EXTRA_DIST = auto_increment.res auto_increment.tst \ insert_and_repair.pl \ grant.pl grant.res test_delayed_insert.pl \ pmail.pl mail_to_db.pl table_types.pl \ - udf_test udf_test.res + udf_test udf_test.res myisam-big-rows.tst # Don't update the files from bitkeeper %::SCCS/s.% |