mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 04:22:27 +01:00
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 sql/mysql_priv.h: Auto merged sql/sql_yacc.yy: Auto merged
This commit is contained in:
commit
7e8ca7fd4b
10 changed files with 81 additions and 115 deletions
|
@ -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 @@ 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()
|
||||
{
|
||||
|
|
|
@ -2030,15 +2030,6 @@ void Item_cond::neg_arguments(THD *thd)
|
|||
{
|
||||
if (!(new_item= new Item_func_not(item)))
|
||||
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));
|
||||
}
|
||||
|
@ -2716,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()).
|
||||
|
@ -2727,25 +2715,13 @@ 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];
|
||||
}
|
||||
|
||||
|
||||
Item *Item_bool_rowready_func2::neg_transformer(THD *thd)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2754,9 +2730,6 @@ Item *Item_bool_rowready_func2::neg_transformer(THD *thd)
|
|||
Item *Item_func_isnull::neg_transformer(THD *thd)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2765,9 +2738,6 @@ Item *Item_func_isnull::neg_transformer(THD *thd)
|
|||
Item *Item_func_isnotnull::neg_transformer(THD *thd)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2777,9 +2747,6 @@ Item *Item_cond_and::neg_transformer(THD *thd) /* NOT(a AND b AND ...) -> */
|
|||
{
|
||||
neg_arguments(thd);
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2789,9 +2756,6 @@ Item *Item_cond_or::neg_transformer(THD *thd) /* NOT(a OR b OR ...) -> */
|
|||
{
|
||||
neg_arguments(thd);
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
@ -274,7 +276,7 @@ public:
|
|||
enum Functype rev_functype() const { return EQUAL_FUNC; }
|
||||
cond_result eq_cmp_result() const { return COND_TRUE; }
|
||||
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
|
|||
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)
|
||||
{
|
||||
|
@ -4401,19 +4347,6 @@ optimize_cond(THD *thd, COND *conds, Item::cond_result *cond_value)
|
|||
if (conds)
|
||||
{
|
||||
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 */
|
||||
propagate_cond_constants((I_List<COND_CMP> *) 0, conds, conds);
|
||||
/*
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -2752,8 +2752,14 @@ simple_expr:
|
|||
| '+' expr %prec NEG { $$= $2; }
|
||||
| '-' expr %prec NEG { $$= new Item_func_neg($2); }
|
||||
| '~' expr %prec NEG { $$= new Item_func_bit_neg($2); }
|
||||
| NOT expr %prec NEG { $$= new Item_func_not($2); }
|
||||
| '!' expr %prec NEG { $$= new Item_func_not($2); }
|
||||
| NOT expr %prec NEG
|
||||
{
|
||||
$$= negate_expression(YYTHD, $2);
|
||||
}
|
||||
| '!' expr %prec NEG
|
||||
{
|
||||
$$= negate_expression(YYTHD, $2);
|
||||
}
|
||||
| '(' expr ')' { $$= $2; }
|
||||
| '(' expr ',' expr_list ')'
|
||||
{
|
||||
|
@ -3595,11 +3601,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();
|
||||
}
|
||||
;
|
||||
|
||||
|
|
Loading…
Reference in a new issue