summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/negation_elimination.result13
-rw-r--r--mysql-test/t/negation_elimination.test4
-rw-r--r--sql/item.h4
-rw-r--r--sql/item_cmpfunc.cc5
-rw-r--r--sql/item_cmpfunc.h3
-rw-r--r--sql/mysql_priv.h4
-rw-r--r--sql/sql_parse.cc36
-rw-r--r--sql/sql_select.cc54
-rw-r--r--sql/sql_select.h1
-rw-r--r--sql/sql_yacc.yy20
10 files changed, 74 insertions, 70 deletions
diff --git a/mysql-test/r/negation_elimination.result b/mysql-test/r/negation_elimination.result
index a3a2bad7ec6..9193a125cd1 100644
--- a/mysql-test/r/negation_elimination.result
+++ b/mysql-test/r/negation_elimination.result
@@ -375,4 +375,17 @@ a
13
14
15
+delete from t1 where a > 3;
+select a, not(not(a)) from t1;
+a not(not(a))
+NULL NULL
+0 0
+1 1
+2 1
+3 1
+explain extended select a, not(not(a)), not(a <= 2 and not(a)), not(a not like "1"), not (a not in (1,2)), not(a != 2) from t1 where not(not(a)) having not(not(a));
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 index NULL a 5 NULL 5 Using where; Using index
+Warnings:
+Note 1003 select test.t1.a AS `a`,(test.t1.a <> 0) AS `not(not(a))`,((test.t1.a > 2) or test.t1.a) AS `not(a <= 2 and not(a))`,(test.t1.a like _latin1'1') AS `not(a not like "1")`,(test.t1.a in (1,2)) AS `not (a not in (1,2))`,(test.t1.a = 2) AS `not(a != 2)` from test.t1 where test.t1.a having test.t1.a
drop table t1;
diff --git a/mysql-test/t/negation_elimination.test b/mysql-test/t/negation_elimination.test
index 49428cc238b..c50a9678edb 100644
--- a/mysql-test/t/negation_elimination.test
+++ b/mysql-test/t/negation_elimination.test
@@ -65,4 +65,8 @@ select * from t1 where not((a < 5 and a < 10) and (not(a > 16) or a > 17));
explain select * from t1 where ((a between 5 and 15) and (not(a like 10)));
select * from t1 where ((a between 5 and 15) and (not(a like 10)));
+delete from t1 where a > 3;
+select a, not(not(a)) from t1;
+explain extended select a, not(not(a)), not(a <= 2 and not(a)), not(a not like "1"), not (a not in (1,2)), not(a != 2) from t1 where not(not(a)) having not(not(a));
+
drop table t1;
diff --git a/sql/item.h b/sql/item.h
index 6900fa11b90..742cf934381 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -239,6 +239,7 @@ public:
virtual void top_level_item() {}
virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; }
+ virtual bool is_bool_func() { return 0; }
virtual void save_in_result_field(bool no_conversions) {}
virtual void no_rows_in_result() {}
virtual Item *copy_or_same(THD *thd) { return this; }
@@ -268,8 +269,7 @@ public:
virtual void bring_value() {}
Field *tmp_table_field_from_field_type(TABLE *table);
-
- /* Used in sql_select.cc:eliminate_not_funcs() */
+
virtual Item *neg_transformer(THD *thd) { return NULL; }
void delete_self()
{
diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc
index de37e858bac..53ec17fd59d 100644
--- a/sql/item_cmpfunc.cc
+++ b/sql/item_cmpfunc.cc
@@ -2707,9 +2707,6 @@ longlong Item_cond_xor::val_int()
IS NULL(a) -> IS NOT NULL(a)
IS NOT NULL(a) -> IS NULL(a)
- NOTE
- This method is used in the eliminate_not_funcs() function.
-
RETURN
New item or
NULL if we cannot apply NOT transformation (see Item::neg_transformer()).
@@ -2718,7 +2715,7 @@ longlong Item_cond_xor::val_int()
Item *Item_func_not::neg_transformer(THD *thd) /* NOT(x) -> x */
{
// We should apply negation elimination to the argument of the NOT function
- return eliminate_not_funcs(thd, args[0]);
+ return args[0];
}
diff --git a/sql/item_cmpfunc.h b/sql/item_cmpfunc.h
index c3551b35d63..f1a2b11aaa8 100644
--- a/sql/item_cmpfunc.h
+++ b/sql/item_cmpfunc.h
@@ -89,6 +89,7 @@ public:
Item_bool_func(Item *a) :Item_int_func(a) {}
Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {}
Item_bool_func(THD *thd, Item_bool_func *item) :Item_int_func(thd, item) {}
+ bool is_bool_func() { return 1; }
void fix_length_and_dec() { decimals=0; max_length=1; }
};
@@ -201,6 +202,7 @@ public:
bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
void print(String *str) { Item_func::print_op(str); }
bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); }
+ bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; }
friend class Arg_comparator;
@@ -748,6 +750,7 @@ class Item_func_in :public Item_int_func
enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; }
bool nulls_in_row();
+ bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
};
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 1949ecf26dc..a9ee6b4b691 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -297,7 +297,8 @@ enum enum_parsing_place
{
NO_MATTER,
IN_HAVING,
- SELECT_LIST
+ SELECT_LIST,
+ IN_WHERE
};
struct st_table;
@@ -376,6 +377,7 @@ int delete_precheck(THD *thd, TABLE_LIST *tables);
int insert_precheck(THD *thd, TABLE_LIST *tables, bool update);
int create_table_precheck(THD *thd, TABLE_LIST *tables,
TABLE_LIST *create_table);
+Item *negate_expression(THD *thd, Item *expr);
#include "sql_class.h"
#include "opt_range.h"
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 3cb356d42c8..79a011b9501 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -5401,3 +5401,39 @@ int create_table_precheck(THD *thd, TABLE_LIST *tables,
check_grant(thd, want_priv, create_table, 0, UINT_MAX, 0)) ?
1 : 0);
}
+
+
+/*
+ negate given expression
+
+ SYNOPSIS
+ negate_expression()
+ thd therad handler
+ expr expression for negation
+
+ RETURN
+ negated expression
+*/
+
+Item *negate_expression(THD *thd, Item *expr)
+{
+ Item *negated;
+ if (expr->type() == Item::FUNC_ITEM &&
+ ((Item_func *) expr)->functype() == Item_func::NOT_FUNC)
+ {
+ /* it is NOT(NOT( ... )) */
+ Item *arg= ((Item_func *) expr)->arguments()[0];
+ enum_parsing_place place= thd->lex->current_select->parsing_place;
+ if (arg->is_bool_func() || place == IN_WHERE || place == IN_HAVING)
+ return arg;
+ /*
+ if it is not boolean function then we have to emulate value of
+ not(not(a)), it will be a != 0
+ */
+ return new Item_func_ne(arg, new Item_int((char*) "0", 0, 1));
+ }
+
+ if ((negated= expr->neg_transformer(thd)) != 0)
+ return negated;
+ return new Item_func_not(expr);
+}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index 701d2597d3d..72e169c77af 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -4339,60 +4339,6 @@ propagate_cond_constants(I_List<COND_CMP> *save_list,COND *and_father,
}
-/*
- Eliminate NOT functions from the condition tree.
-
- SYNPOSIS
- eliminate_not_funcs()
- thd thread handler
- cond condition tree
-
- DESCRIPTION
- Eliminate NOT functions from the condition tree where it's possible.
- Recursively traverse condition tree to find all NOT functions.
- Call neg_transformer() method for negated arguments.
-
- NOTE
- If neg_transformer() returned a new condition we call fix_fields().
- We don't delete any items as it's not needed. They will be deleted
- later at once.
-
- RETURN
- New condition tree
-*/
-
-COND *eliminate_not_funcs(THD *thd, COND *cond)
-{
- if (!cond)
- return cond;
- if (cond->type() == Item::COND_ITEM) /* OR or AND */
- {
- List_iterator<Item> li(*((Item_cond*) cond)->argument_list());
- Item *item;
- while ((item= li++))
- {
- Item *new_item= eliminate_not_funcs(thd, item);
- if (item != new_item)
- VOID(li.replace(new_item)); /* replace item with a new condition */
- }
- }
- else if (cond->type() == Item::FUNC_ITEM && /* 'NOT' operation? */
- ((Item_func*) cond)->functype() == Item_func::NOT_FUNC)
- {
- COND *new_cond= ((Item_func*) cond)->arguments()[0]->neg_transformer(thd);
- if (new_cond)
- {
- /*
- Here we can delete the NOT function. Something like: delete cond;
- But we don't need to do it. All items will be deleted later at once.
- */
- cond= new_cond;
- }
- }
- return cond;
-}
-
-
static COND *
optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value)
{
diff --git a/sql/sql_select.h b/sql/sql_select.h
index 8aca43484d2..34eaa7e272d 100644
--- a/sql/sql_select.h
+++ b/sql/sql_select.h
@@ -438,4 +438,3 @@ bool cp_buffer_from_ref(TABLE_REF *ref);
bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab);
-COND *eliminate_not_funcs(THD *thd, COND *cond);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index afb55463ad1..fa772a9cf11 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -2757,13 +2757,11 @@ simple_expr:
| '~' expr %prec NEG { $$= new Item_func_bit_neg($2); }
| NOT expr %prec NEG
{
- if (($$= $2->neg_transformer(YYTHD)) == 0)
- $$= new Item_func_not($2);
+ $$= negate_expression(YYTHD, $2);
}
| '!' expr %prec NEG
{
- if (($$= $2->neg_transformer(YYTHD)) == 0)
- $$= new Item_func_not($2);
+ $$= negate_expression(YYTHD, $2);
}
| '(' expr ')' { $$= $2; }
| '(' expr ',' expr_list ')'
@@ -3606,11 +3604,17 @@ opt_all:
where_clause:
/* empty */ { Select->where= 0; }
- | WHERE expr
+ | WHERE
+ {
+ Select->parsing_place= IN_WHERE;
+ }
+ expr
{
- Select->where= $2;
- if ($2)
- $2->top_level_item();
+ SELECT_LEX *select= Select;
+ select->where= $3;
+ select->parsing_place= NO_MATTER;
+ if ($3)
+ $3->top_level_item();
}
;