mirror of
https://github.com/MariaDB/server.git
synced 2025-01-17 12:32:27 +01:00
Merge
This commit is contained in:
commit
419c20f10a
7 changed files with 236 additions and 73 deletions
|
@ -375,6 +375,121 @@ a
|
|||
13
|
||||
14
|
||||
15
|
||||
# XOR (Note: XOR is negated by negating one of the operands)
|
||||
# Should return 6,7
|
||||
SELECT * FROM t1 WHERE ((a > 5) XOR (a > 7));
|
||||
a
|
||||
6
|
||||
7
|
||||
# Should return 0..5,8..19
|
||||
SELECT * FROM t1 WHERE ((NOT (a > 5)) XOR (a > 7));
|
||||
a
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
13
|
||||
14
|
||||
15
|
||||
16
|
||||
17
|
||||
18
|
||||
19
|
||||
SELECT * FROM t1 WHERE ((a > 5) XOR (NOT (a > 7)));
|
||||
a
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
13
|
||||
14
|
||||
15
|
||||
16
|
||||
17
|
||||
18
|
||||
19
|
||||
SELECT * FROM t1 WHERE NOT ((a > 5) XOR (a > 7));
|
||||
a
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
13
|
||||
14
|
||||
15
|
||||
16
|
||||
17
|
||||
18
|
||||
19
|
||||
# Should return 6,7
|
||||
SELECT * FROM t1 WHERE NOT ((NOT (a > 5)) XOR (a > 7));
|
||||
a
|
||||
6
|
||||
7
|
||||
SELECT * FROM t1 WHERE NOT ((a > 5) XOR (NOT (a > 7)));
|
||||
a
|
||||
6
|
||||
7
|
||||
# Should return 0..5,8..19
|
||||
SELECT * FROM t1 WHERE NOT ((NOT (a > 5)) XOR (NOT (a > 7)));
|
||||
a
|
||||
0
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
8
|
||||
9
|
||||
10
|
||||
11
|
||||
12
|
||||
13
|
||||
14
|
||||
15
|
||||
16
|
||||
17
|
||||
18
|
||||
19
|
||||
# Should have empty result
|
||||
SELECT * FROM t1 WHERE (NULL XOR (a > 7));
|
||||
a
|
||||
SELECT * FROM t1 WHERE NOT (NULL XOR (a > 7));
|
||||
a
|
||||
# Should be simplified to "...WHERE (a XOR a)
|
||||
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NOT ((NOT a) XOR (a));
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE t1 index NULL a 5 NULL 21 100.00 Using where; Using index
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` xor `test`.`t1`.`a`)
|
||||
# Should be simplified to "...WHERE (a XOR a)
|
||||
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NOT (a XOR (NOT a));
|
||||
id select_type table type possible_keys key key_len ref rows filtered Extra
|
||||
1 SIMPLE t1 index NULL a 5 NULL 21 100.00 Using where; Using index
|
||||
Warnings:
|
||||
Note 1003 select `test`.`t1`.`a` AS `a` from `test`.`t1` where (`test`.`t1`.`a` xor `test`.`t1`.`a`)
|
||||
# End XOR
|
||||
delete from t1 where a > 3;
|
||||
select a, not(not(a)) from t1;
|
||||
a not(not(a))
|
||||
|
|
|
@ -65,6 +65,35 @@ 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)));
|
||||
|
||||
--echo # XOR (Note: XOR is negated by negating one of the operands)
|
||||
|
||||
--echo # Should return 6,7
|
||||
SELECT * FROM t1 WHERE ((a > 5) XOR (a > 7));
|
||||
|
||||
--echo # Should return 0..5,8..19
|
||||
SELECT * FROM t1 WHERE ((NOT (a > 5)) XOR (a > 7));
|
||||
SELECT * FROM t1 WHERE ((a > 5) XOR (NOT (a > 7)));
|
||||
SELECT * FROM t1 WHERE NOT ((a > 5) XOR (a > 7));
|
||||
|
||||
--echo # Should return 6,7
|
||||
SELECT * FROM t1 WHERE NOT ((NOT (a > 5)) XOR (a > 7));
|
||||
SELECT * FROM t1 WHERE NOT ((a > 5) XOR (NOT (a > 7)));
|
||||
|
||||
--echo # Should return 0..5,8..19
|
||||
SELECT * FROM t1 WHERE NOT ((NOT (a > 5)) XOR (NOT (a > 7)));
|
||||
|
||||
--echo # Should have empty result
|
||||
SELECT * FROM t1 WHERE (NULL XOR (a > 7));
|
||||
SELECT * FROM t1 WHERE NOT (NULL XOR (a > 7));
|
||||
|
||||
--echo # Should be simplified to "...WHERE (a XOR a)
|
||||
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NOT ((NOT a) XOR (a));
|
||||
|
||||
--echo # Should be simplified to "...WHERE (a XOR a)
|
||||
EXPLAIN EXTENDED SELECT * FROM t1 WHERE NOT (a XOR (NOT a));
|
||||
|
||||
--echo # End XOR
|
||||
|
||||
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));
|
||||
|
|
|
@ -5065,23 +5065,21 @@ bool Item_func_like::turboBM_matches(const char* text, int text_len) const
|
|||
very fast to use.
|
||||
*/
|
||||
|
||||
longlong Item_cond_xor::val_int()
|
||||
longlong Item_func_xor::val_int()
|
||||
{
|
||||
DBUG_ASSERT(fixed == 1);
|
||||
List_iterator<Item> li(list);
|
||||
Item *item;
|
||||
int result=0;
|
||||
null_value=0;
|
||||
while ((item=li++))
|
||||
int result= 0;
|
||||
null_value= false;
|
||||
for (uint i= 0; i < arg_count; i++)
|
||||
{
|
||||
result^= (item->val_int() != 0);
|
||||
if (item->null_value)
|
||||
result^= (args[i]->val_int() != 0);
|
||||
if (args[i]->null_value)
|
||||
{
|
||||
null_value=1;
|
||||
null_value= true;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return (longlong) result;
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -5122,6 +5120,33 @@ Item *Item_bool_rowready_func2::neg_transformer(THD *thd)
|
|||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
XOR can be negated by negating one of the operands:
|
||||
|
||||
NOT (a XOR b) => (NOT a) XOR b
|
||||
=> a XOR (NOT b)
|
||||
|
||||
@param thd Thread handle
|
||||
@return New negated item
|
||||
*/
|
||||
Item *Item_func_xor::neg_transformer(THD *thd)
|
||||
{
|
||||
Item *neg_operand;
|
||||
Item_func_xor *new_item;
|
||||
if ((neg_operand= args[0]->neg_transformer(thd)))
|
||||
// args[0] has neg_tranformer
|
||||
new_item= new(thd->mem_root) Item_func_xor(neg_operand, args[1]);
|
||||
else if ((neg_operand= args[1]->neg_transformer(thd)))
|
||||
// args[1] has neg_tranformer
|
||||
new_item= new(thd->mem_root) Item_func_xor(args[0], neg_operand);
|
||||
else
|
||||
{
|
||||
neg_operand= new(thd->mem_root) Item_func_not(args[0]);
|
||||
new_item= new(thd->mem_root) Item_func_xor(neg_operand, args[1]);
|
||||
}
|
||||
return new_item;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
a IS NULL -> a IS NOT NULL.
|
||||
|
|
|
@ -391,6 +391,22 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
/**
|
||||
XOR inherits from Item_bool_func2 because it is not optimized yet.
|
||||
Later, when XOR is optimized, it needs to inherit from
|
||||
Item_cond instead. See WL#5800.
|
||||
*/
|
||||
class Item_func_xor :public Item_bool_func2
|
||||
{
|
||||
public:
|
||||
Item_func_xor(Item *i1, Item *i2) :Item_bool_func2(i1, i2) {}
|
||||
enum Functype functype() const { return XOR_FUNC; }
|
||||
const char *func_name() const { return "xor"; }
|
||||
longlong val_int();
|
||||
void top_level_item() {}
|
||||
Item *neg_transformer(THD *thd);
|
||||
};
|
||||
|
||||
class Item_func_not :public Item_bool_func
|
||||
{
|
||||
public:
|
||||
|
@ -1817,45 +1833,6 @@ inline bool is_cond_or(Item *item)
|
|||
return (cond_item->functype() == Item_func::COND_OR_FUNC);
|
||||
}
|
||||
|
||||
/*
|
||||
XOR is Item_cond, not an Item_int_func because we could like to
|
||||
optimize (a XOR b) later on. It's low prio, though
|
||||
*/
|
||||
|
||||
class Item_cond_xor :public Item_cond
|
||||
{
|
||||
public:
|
||||
Item_cond_xor(Item *i1,Item *i2) :Item_cond(i1,i2)
|
||||
{
|
||||
/*
|
||||
Items must be stored in args[] as well because this Item_cond is
|
||||
treated as a FUNC_ITEM (see type()). I.e., users of it will get
|
||||
it's children by calling arguments(), not argument_list(). This
|
||||
is a temporary solution until XOR is optimized and treated like
|
||||
a full Item_cond citizen.
|
||||
*/
|
||||
arg_count= 2;
|
||||
args= tmp_arg;
|
||||
args[0]= i1;
|
||||
args[1]= i2;
|
||||
}
|
||||
enum Functype functype() const { return COND_XOR_FUNC; }
|
||||
/* TODO: remove the next line when implementing XOR optimization */
|
||||
enum Type type() const { return FUNC_ITEM; }
|
||||
longlong val_int();
|
||||
const char *func_name() const { return "xor"; }
|
||||
void top_level_item() {}
|
||||
/* Since child Items are stored in args[], Items cannot be added.
|
||||
However, since Item_cond_xor is treated as a FUNC_ITEM (see
|
||||
type()), the methods below should never be called.
|
||||
*/
|
||||
bool add(Item *item) { DBUG_ASSERT(FALSE); return FALSE; }
|
||||
bool add_at_head(Item *item) { DBUG_ASSERT(FALSE); return FALSE; }
|
||||
bool add_at_head(List<Item> *nlist) { DBUG_ASSERT(FALSE); return FALSE; }
|
||||
void copy_andor_arguments(THD *thd, Item_cond *item) { DBUG_ASSERT(FALSE); }
|
||||
};
|
||||
|
||||
|
||||
/* Some useful inline functions */
|
||||
|
||||
inline Item *and_conds(Item *a, Item *b)
|
||||
|
|
|
@ -44,7 +44,7 @@ public:
|
|||
enum Functype { UNKNOWN_FUNC,EQ_FUNC,EQUAL_FUNC,NE_FUNC,LT_FUNC,LE_FUNC,
|
||||
GE_FUNC,GT_FUNC,FT_FUNC,
|
||||
LIKE_FUNC,ISNULL_FUNC,ISNOTNULL_FUNC,
|
||||
COND_AND_FUNC, COND_OR_FUNC, COND_XOR_FUNC,
|
||||
COND_AND_FUNC, COND_OR_FUNC, XOR_FUNC,
|
||||
BETWEEN, IN_FUNC, MULT_EQUAL_FUNC,
|
||||
INTERVAL_FUNC, ISNOTNULLTEST_FUNC,
|
||||
SP_EQUALS_FUNC, SP_DISJOINT_FUNC,SP_INTERSECTS_FUNC,
|
||||
|
|
|
@ -183,7 +183,7 @@ static bool convert_subq_to_sj(JOIN *parent_join, Item_in_subselect *subq_pred);
|
|||
static bool convert_subq_to_jtbm(JOIN *parent_join,
|
||||
Item_in_subselect *subq_pred, bool *remove);
|
||||
static TABLE_LIST *alloc_join_nest(THD *thd);
|
||||
static uint get_tmp_table_rec_length(List<Item> &items);
|
||||
static uint get_tmp_table_rec_length(Item **p_list, uint elements);
|
||||
static double get_tmp_table_lookup_cost(THD *thd, double row_count,
|
||||
uint row_size);
|
||||
static double get_tmp_table_write_cost(THD *thd, double row_count,
|
||||
|
@ -1806,8 +1806,11 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
|
|||
sjm->materialization_cost.convert_from_cost(subjoin_read_time);
|
||||
sjm->rows= subjoin_out_rows;
|
||||
|
||||
List<Item> &right_expr_list=
|
||||
sj_nest->sj_subq_pred->unit->first_select()->item_list;
|
||||
// Don't use the following list because it has "stale" items. use
|
||||
// ref_pointer_array instead:
|
||||
//
|
||||
//List<Item> &right_expr_list=
|
||||
// sj_nest->sj_subq_pred->unit->first_select()->item_list;
|
||||
/*
|
||||
Adjust output cardinality estimates. If the subquery has form
|
||||
|
||||
|
@ -1825,17 +1828,20 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
|
|||
|
||||
See also get_post_group_estimate().
|
||||
*/
|
||||
SELECT_LEX *subq_select= sj_nest->sj_subq_pred->unit->first_select();
|
||||
{
|
||||
for (uint i=0 ; i < join->const_tables + sjm->tables ; i++)
|
||||
{
|
||||
JOIN_TAB *tab= join->best_positions[i].table;
|
||||
join->map2table[tab->table->tablenr]= tab;
|
||||
}
|
||||
List_iterator<Item> it(right_expr_list);
|
||||
Item *item;
|
||||
//List_iterator<Item> it(right_expr_list);
|
||||
Item **ref_array= subq_select->ref_pointer_array;
|
||||
Item **ref_array_end= ref_array + subq_select->item_list.elements;
|
||||
table_map map= 0;
|
||||
while ((item= it++))
|
||||
map |= item->used_tables();
|
||||
//while ((item= it++))
|
||||
for (;ref_array < ref_array_end; ref_array++)
|
||||
map |= (*ref_array)->used_tables();
|
||||
map= map & ~PSEUDO_TABLE_BITS;
|
||||
Table_map_iterator tm_it(map);
|
||||
int tableno;
|
||||
|
@ -1850,7 +1856,8 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
|
|||
/*
|
||||
Calculate temporary table parameters and usage costs
|
||||
*/
|
||||
uint rowlen= get_tmp_table_rec_length(right_expr_list);
|
||||
uint rowlen= get_tmp_table_rec_length(subq_select->ref_pointer_array,
|
||||
subq_select->item_list.elements);
|
||||
double lookup_cost= get_tmp_table_lookup_cost(join->thd,
|
||||
subjoin_out_rows, rowlen);
|
||||
double write_cost= get_tmp_table_write_cost(join->thd,
|
||||
|
@ -1897,13 +1904,15 @@ bool optimize_semijoin_nests(JOIN *join, table_map all_table_map)
|
|||
Length of the temptable record, in bytes
|
||||
*/
|
||||
|
||||
static uint get_tmp_table_rec_length(List<Item> &items)
|
||||
static uint get_tmp_table_rec_length(Item **p_items, uint elements)
|
||||
{
|
||||
uint len= 0;
|
||||
Item *item;
|
||||
List_iterator<Item> it(items);
|
||||
while ((item= it++))
|
||||
//List_iterator<Item> it(items);
|
||||
Item **p_item;
|
||||
for (p_item= p_items; p_item < p_items + elements ; p_item++)
|
||||
{
|
||||
item = *p_item;
|
||||
switch (item->result_type()) {
|
||||
case REAL_RESULT:
|
||||
len += sizeof(double);
|
||||
|
@ -2908,19 +2917,23 @@ bool setup_sj_materialization_part1(JOIN_TAB *sjm_tab)
|
|||
SJ_MATERIALIZATION_INFO *sjm= emb_sj_nest->sj_mat_info;
|
||||
THD *thd= tab->join->thd;
|
||||
/* First the calls come to the materialization function */
|
||||
List<Item> &item_list= emb_sj_nest->sj_subq_pred->unit->first_select()->item_list;
|
||||
//List<Item> &item_list= emb_sj_nest->sj_subq_pred->unit->first_select()->item_list;
|
||||
|
||||
DBUG_ASSERT(sjm->is_used);
|
||||
/*
|
||||
Set up the table to write to, do as select_union::create_result_table does
|
||||
*/
|
||||
sjm->sjm_table_param.init();
|
||||
sjm->sjm_table_param.field_count= item_list.elements;
|
||||
sjm->sjm_table_param.bit_fields_as_long= TRUE;
|
||||
List_iterator<Item> it(item_list);
|
||||
Item *right_expr;
|
||||
while((right_expr= it++))
|
||||
sjm->sjm_table_cols.push_back(right_expr);
|
||||
//List_iterator<Item> it(item_list);
|
||||
SELECT_LEX *subq_select= emb_sj_nest->sj_subq_pred->unit->first_select();
|
||||
Item **p_item= subq_select->ref_pointer_array;
|
||||
Item **p_end= p_item + subq_select->item_list.elements;
|
||||
//while((right_expr= it++))
|
||||
for(;p_item != p_end; p_item++)
|
||||
sjm->sjm_table_cols.push_back(*p_item);
|
||||
|
||||
sjm->sjm_table_param.field_count= subq_select->item_list.elements;
|
||||
|
||||
if (!(sjm->table= create_tmp_table(thd, &sjm->sjm_table_param,
|
||||
sjm->sjm_table_cols, (ORDER*) 0,
|
||||
|
@ -2952,8 +2965,8 @@ bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab)
|
|||
SJ_MATERIALIZATION_INFO *sjm= emb_sj_nest->sj_mat_info;
|
||||
THD *thd= tab->join->thd;
|
||||
uint i;
|
||||
List<Item> &item_list= emb_sj_nest->sj_subq_pred->unit->first_select()->item_list;
|
||||
List_iterator<Item> it(item_list);
|
||||
//List<Item> &item_list= emb_sj_nest->sj_subq_pred->unit->first_select()->item_list;
|
||||
//List_iterator<Item> it(item_list);
|
||||
|
||||
if (!sjm->is_sj_scan)
|
||||
{
|
||||
|
@ -3069,11 +3082,13 @@ bool setup_sj_materialization_part2(JOIN_TAB *sjm_tab)
|
|||
*/
|
||||
sjm->copy_field= new Copy_field[sjm->sjm_table_cols.elements];
|
||||
//it.rewind();
|
||||
Item **p_item= emb_sj_nest->sj_subq_pred->unit->first_select()->ref_pointer_array;
|
||||
for (uint i=0; i < sjm->sjm_table_cols.elements; i++)
|
||||
{
|
||||
bool dummy;
|
||||
Item_equal *item_eq;
|
||||
Item *item= (it++)->real_item();
|
||||
//Item *item= (it++)->real_item();
|
||||
Item *item= (*(p_item++))->real_item();
|
||||
DBUG_ASSERT(item->type() == Item::FIELD_ITEM);
|
||||
Field *copy_to= ((Item_field*)item)->field;
|
||||
/*
|
||||
|
@ -4513,7 +4528,9 @@ bool JOIN::choose_subquery_plan(table_map join_tables)
|
|||
C. Compute execution costs.
|
||||
*/
|
||||
/* C.1 Compute the cost of the materialization strategy. */
|
||||
uint rowlen= get_tmp_table_rec_length(unit->first_select()->item_list);
|
||||
//uint rowlen= get_tmp_table_rec_length(unit->first_select()->item_list);
|
||||
uint rowlen= get_tmp_table_rec_length(ref_pointer_array,
|
||||
select_lex->item_list.elements);
|
||||
/* The cost of writing one row into the temporary table. */
|
||||
double write_cost= get_tmp_table_write_cost(thd, inner_record_count_1,
|
||||
rowlen);
|
||||
|
|
|
@ -7172,7 +7172,7 @@ expr:
|
|||
| expr XOR expr %prec XOR
|
||||
{
|
||||
/* XOR is a proprietary extension */
|
||||
$$ = new (YYTHD->mem_root) Item_cond_xor($1, $3);
|
||||
$$ = new (YYTHD->mem_root) Item_func_xor($1, $3);
|
||||
if ($$ == NULL)
|
||||
MYSQL_YYABORT;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue