Commit b02451c5 authored by bell@sanja.is.com.ua's avatar bell@sanja.is.com.ua

Merge sanja.is.com.ua:/home/bell/mysql/bk/mysql-4.1

into sanja.is.com.ua:/home/bell/mysql/bk/work-not-4.1
parents ae801bad 2cf1234b
...@@ -375,4 +375,17 @@ a ...@@ -375,4 +375,17 @@ a
13 13
14 14
15 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; drop table t1;
...@@ -65,4 +65,8 @@ select * from t1 where not((a < 5 and a < 10) and (not(a > 16) or a > 17)); ...@@ -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))); 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))); 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; drop table t1;
...@@ -239,6 +239,7 @@ class Item { ...@@ -239,6 +239,7 @@ class Item {
virtual void top_level_item() {} virtual void top_level_item() {}
virtual void set_result_field(Field *field) {} virtual void set_result_field(Field *field) {}
virtual bool is_result_field() { return 0; } 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 save_in_result_field(bool no_conversions) {}
virtual void no_rows_in_result() {} virtual void no_rows_in_result() {}
virtual Item *copy_or_same(THD *thd) { return this; } virtual Item *copy_or_same(THD *thd) { return this; }
...@@ -268,8 +269,7 @@ class Item { ...@@ -268,8 +269,7 @@ class Item {
virtual void bring_value() {} virtual void bring_value() {}
Field *tmp_table_field_from_field_type(TABLE *table); 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; } virtual Item *neg_transformer(THD *thd) { return NULL; }
void delete_self() void delete_self()
{ {
......
...@@ -2030,15 +2030,6 @@ void Item_cond::neg_arguments(THD *thd) ...@@ -2030,15 +2030,6 @@ void Item_cond::neg_arguments(THD *thd)
{ {
if (!(new_item= new Item_func_not(item))) if (!(new_item= new Item_func_not(item)))
return; // Fatal OEM error return; // Fatal OEM error
/*
We can use 0 as tables list because Item_func_not do not use it
on fix_fields and its arguments are already fixed.
We do not check results of fix_fields, because there are not way
to return error in this functions interface, thd->net.report_error
will be checked on upper level call.
*/
new_item->fix_fields(thd, 0, &new_item);
} }
VOID(li.replace(new_item)); VOID(li.replace(new_item));
} }
...@@ -2716,9 +2707,6 @@ longlong Item_cond_xor::val_int() ...@@ -2716,9 +2707,6 @@ longlong Item_cond_xor::val_int()
IS NULL(a) -> IS NOT NULL(a) IS NULL(a) -> IS NOT NULL(a)
IS NOT NULL(a) -> IS NULL(a) IS NOT NULL(a) -> IS NULL(a)
NOTE
This method is used in the eliminate_not_funcs() function.
RETURN RETURN
New item or New item or
NULL if we cannot apply NOT transformation (see Item::neg_transformer()). NULL if we cannot apply NOT transformation (see Item::neg_transformer()).
...@@ -2727,25 +2715,13 @@ longlong Item_cond_xor::val_int() ...@@ -2727,25 +2715,13 @@ longlong Item_cond_xor::val_int()
Item *Item_func_not::neg_transformer(THD *thd) /* NOT(x) -> x */ Item *Item_func_not::neg_transformer(THD *thd) /* NOT(x) -> x */
{ {
// We should apply negation elimination to the argument of the NOT function // We should apply negation elimination to the argument of the NOT function
return eliminate_not_funcs(thd, args[0]); return args[0];
} }
Item *Item_bool_rowready_func2::neg_transformer(THD *thd) Item *Item_bool_rowready_func2::neg_transformer(THD *thd)
{ {
Item *item= negated_item(); Item *item= negated_item();
if (item)
{
/*
We can use 0 as tables list because Item_func* family do not use it
on fix_fields and its arguments are already fixed.
We do not check results of fix_fields, because there are not way
to return error in this functions interface, thd->net.report_error
will be checked on upper level call.
*/
item->fix_fields(thd, 0, &item);
}
return item; return item;
} }
...@@ -2754,9 +2730,6 @@ Item *Item_bool_rowready_func2::neg_transformer(THD *thd) ...@@ -2754,9 +2730,6 @@ Item *Item_bool_rowready_func2::neg_transformer(THD *thd)
Item *Item_func_isnull::neg_transformer(THD *thd) Item *Item_func_isnull::neg_transformer(THD *thd)
{ {
Item *item= new Item_func_isnotnull(args[0]); Item *item= new Item_func_isnotnull(args[0]);
// see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
if (item)
item->fix_fields(thd, 0, &item);
return item; return item;
} }
...@@ -2765,9 +2738,6 @@ Item *Item_func_isnull::neg_transformer(THD *thd) ...@@ -2765,9 +2738,6 @@ Item *Item_func_isnull::neg_transformer(THD *thd)
Item *Item_func_isnotnull::neg_transformer(THD *thd) Item *Item_func_isnotnull::neg_transformer(THD *thd)
{ {
Item *item= new Item_func_isnull(args[0]); Item *item= new Item_func_isnull(args[0]);
// see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
if (item)
item->fix_fields(thd, 0, &item);
return item; return item;
} }
...@@ -2777,9 +2747,6 @@ Item *Item_cond_and::neg_transformer(THD *thd) /* NOT(a AND b AND ...) -> */ ...@@ -2777,9 +2747,6 @@ Item *Item_cond_and::neg_transformer(THD *thd) /* NOT(a AND b AND ...) -> */
{ {
neg_arguments(thd); neg_arguments(thd);
Item *item= new Item_cond_or(list); Item *item= new Item_cond_or(list);
// see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
if (item)
item->fix_fields(thd, 0, &item);
return item; return item;
} }
...@@ -2789,9 +2756,6 @@ Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */ ...@@ -2789,9 +2756,6 @@ Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */
{ {
neg_arguments(thd); neg_arguments(thd);
Item *item= new Item_cond_and(list); Item *item= new Item_cond_and(list);
// see comment before fix_fields in Item_bool_rowready_func2::neg_transformer
if (item)
item->fix_fields(thd, 0, &item);
return item; return item;
} }
......
...@@ -89,6 +89,7 @@ class Item_bool_func :public Item_int_func ...@@ -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_int_func(a) {}
Item_bool_func(Item *a,Item *b) :Item_int_func(a,b) {} 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) {} 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; } void fix_length_and_dec() { decimals=0; max_length=1; }
}; };
...@@ -201,6 +202,7 @@ class Item_bool_func2 :public Item_int_func ...@@ -201,6 +202,7 @@ class Item_bool_func2 :public Item_int_func
bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; } bool have_rev_func() const { return rev_functype() != UNKNOWN_FUNC; }
void print(String *str) { Item_func::print_op(str); } void print(String *str) { Item_func::print_op(str); }
bool is_null() { return test(args[0]->is_null() || args[1]->is_null()); } 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; } CHARSET_INFO *compare_collation() { return cmp.cmp_collation.collation; }
friend class Arg_comparator; friend class Arg_comparator;
...@@ -274,7 +276,7 @@ class Item_func_equal :public Item_bool_rowready_func2 ...@@ -274,7 +276,7 @@ class Item_func_equal :public Item_bool_rowready_func2
enum Functype rev_functype() const { return EQUAL_FUNC; } enum Functype rev_functype() const { return EQUAL_FUNC; }
cond_result eq_cmp_result() const { return COND_TRUE; } cond_result eq_cmp_result() const { return COND_TRUE; }
const char *func_name() const { return "<=>"; } const char *func_name() const { return "<=>"; }
Item* neg_transformer(THD *thd) { return 0; } Item *neg_transformer(THD *thd) { return 0; }
}; };
...@@ -748,6 +750,7 @@ class Item_func_in :public Item_int_func ...@@ -748,6 +750,7 @@ class Item_func_in :public Item_int_func
enum Functype functype() const { return IN_FUNC; } enum Functype functype() const { return IN_FUNC; }
const char *func_name() const { return " IN "; } const char *func_name() const { return " IN "; }
bool nulls_in_row(); bool nulls_in_row();
bool is_bool_func() { return 1; }
CHARSET_INFO *compare_collation() { return cmp_collation.collation; } CHARSET_INFO *compare_collation() { return cmp_collation.collation; }
}; };
......
...@@ -297,7 +297,8 @@ enum enum_parsing_place ...@@ -297,7 +297,8 @@ enum enum_parsing_place
{ {
NO_MATTER, NO_MATTER,
IN_HAVING, IN_HAVING,
SELECT_LIST SELECT_LIST,
IN_WHERE
}; };
struct st_table; struct st_table;
...@@ -376,6 +377,7 @@ int delete_precheck(THD *thd, TABLE_LIST *tables); ...@@ -376,6 +377,7 @@ int delete_precheck(THD *thd, TABLE_LIST *tables);
int insert_precheck(THD *thd, TABLE_LIST *tables, bool update); int insert_precheck(THD *thd, TABLE_LIST *tables, bool update);
int create_table_precheck(THD *thd, TABLE_LIST *tables, int create_table_precheck(THD *thd, TABLE_LIST *tables,
TABLE_LIST *create_table); TABLE_LIST *create_table);
Item *negate_expression(THD *thd, Item *expr);
#include "sql_class.h" #include "sql_class.h"
#include "opt_range.h" #include "opt_range.h"
......
...@@ -5401,3 +5401,39 @@ int create_table_precheck(THD *thd, TABLE_LIST *tables, ...@@ -5401,3 +5401,39 @@ int create_table_precheck(THD *thd, TABLE_LIST *tables,
check_grant(thd, want_priv, create_table, 0, UINT_MAX, 0)) ? check_grant(thd, want_priv, create_table, 0, UINT_MAX, 0)) ?
1 : 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, ...@@ -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 * static COND *
optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value) optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value)
{ {
...@@ -4401,19 +4347,6 @@ optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value) ...@@ -4401,19 +4347,6 @@ optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value)
if (conds) if (conds)
{ {
DBUG_EXECUTE("where", print_where(conds, "original");); DBUG_EXECUTE("where", print_where(conds, "original"););
/* Eliminate NOT operators; in case of PS/SP do it once */
if (thd->current_arena->is_first_stmt_execute())
{
Item_arena *arena= thd->current_arena, backup;
thd->set_n_backup_item_arena(arena, &backup);
conds= eliminate_not_funcs(thd, conds);
select->prep_where= conds->copy_andor_structure(thd);
thd->restore_backup_item_arena(arena, &backup);
}
else
conds= eliminate_not_funcs(thd, conds);
DBUG_EXECUTE("where", print_where(conds, "after negation elimination"););
/* change field = field to field = const for each found field = const */ /* change field = field to field = const for each found field = const */
propagate_cond_constants((I_List<COND_CMP> *) 0, conds, conds); propagate_cond_constants((I_List<COND_CMP> *) 0, conds, conds);
/* /*
......
...@@ -438,4 +438,3 @@ bool cp_buffer_from_ref(TABLE_REF *ref); ...@@ -438,4 +438,3 @@ bool cp_buffer_from_ref(TABLE_REF *ref);
bool error_if_full_join(JOIN *join); bool error_if_full_join(JOIN *join);
int report_error(TABLE *table, int error); int report_error(TABLE *table, int error);
int safe_index_read(JOIN_TAB *tab); int safe_index_read(JOIN_TAB *tab);
COND *eliminate_not_funcs(THD *thd, COND *cond);
...@@ -2752,8 +2752,14 @@ simple_expr: ...@@ -2752,8 +2752,14 @@ simple_expr:
| '+' expr %prec NEG { $$= $2; } | '+' expr %prec NEG { $$= $2; }
| '-' expr %prec NEG { $$= new Item_func_neg($2); } | '-' expr %prec NEG { $$= new Item_func_neg($2); }
| '~' expr %prec NEG { $$= new Item_func_bit_neg($2); } | '~' expr %prec NEG { $$= new Item_func_bit_neg($2); }
| NOT expr %prec NEG { $$= new Item_func_not($2); } | NOT expr %prec NEG
| '!' expr %prec NEG { $$= new Item_func_not($2); } {
$$= negate_expression(YYTHD, $2);
}
| '!' expr %prec NEG
{
$$= negate_expression(YYTHD, $2);
}
| '(' expr ')' { $$= $2; } | '(' expr ')' { $$= $2; }
| '(' expr ',' expr_list ')' | '(' expr ',' expr_list ')'
{ {
...@@ -3595,11 +3601,17 @@ opt_all: ...@@ -3595,11 +3601,17 @@ opt_all:
where_clause: where_clause:
/* empty */ { Select->where= 0; } /* empty */ { Select->where= 0; }
| WHERE expr | WHERE
{
Select->parsing_place= IN_WHERE;
}
expr
{ {
Select->where= $2; SELECT_LEX *select= Select;
if ($2) select->where= $3;
$2->top_level_item(); 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