Commit e6fbc582 authored by unknown's avatar unknown

after review patch


mysql-test/r/negation_elimination.result:
  new tests of negation elimination
mysql-test/t/negation_elimination.test:
  new tests of negation elimination
sql/item.h:
  test of boolean functions added
sql/item_cmpfunc.cc:
  NOT subtree is already checked, so wee need to return just argument
sql/item_cmpfunc.h:
  test of boolean functions added
sql/mysql_priv.h:
  'place' to detect WHERE clause
sql/sql_parse.cc:
  function for creation negated expression
sql/sql_select.cc:
  removed unused function
sql/sql_select.h:
  removed unused function
sql/sql_yacc.yy:
  'place' to detect WHERE clause
parent 6a890621
......@@ -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;
......@@ -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;
......@@ -239,6 +239,7 @@ class Item {
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 @@ class Item {
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()
{
......
......@@ -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];
}
......
......@@ -89,6 +89,7 @@ class Item_bool_func :public Item_int_func
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 @@ class Item_bool_func2 :public Item_int_func
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; }
};
......
......@@ -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"
......
......@@ -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);
}
......@@ -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)
{
......
......@@ -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);
......@@ -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();
}
;
......
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