diff options
author | unknown <bell@sanja.is.com.ua> | 2003-08-12 12:38:03 +0300 |
---|---|---|
committer | unknown <bell@sanja.is.com.ua> | 2003-08-12 12:38:03 +0300 |
commit | 4a36d2ada66e1aa4d685b1b69094ff5226b24e5f (patch) | |
tree | bf79484f7cc14e515e3fc508ecb3815329621ca3 /sql | |
parent | 168b5179794a8ee3fc09dbaba4dcdf0f724f3312 (diff) | |
download | mariadb-git-4a36d2ada66e1aa4d685b1b69094ff5226b24e5f.tar.gz |
optimisation of independent ALL/ANY with aggregate function (WL#1115) (SCRUM)
mysql-test/r/subselect.result:
test of new optimisation
mysql-test/t/subselect.test:
test of new optimisation
sql/item_subselect.cc:
special subselect to finding max/min of returned values
optimisation of independent ALL/ANY with aggregate function
sql/item_subselect.h:
special subselect to finding max/min of returned values
sql/sql_class.cc:
class for collaction result for max/min subquery
sql/sql_class.h:
class for collaction result for max/min subquery
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item_subselect.cc | 84 | ||||
-rw-r--r-- | sql/item_subselect.h | 10 | ||||
-rw-r--r-- | sql/sql_class.cc | 89 | ||||
-rw-r--r-- | sql/sql_class.h | 16 |
4 files changed, 169 insertions, 30 deletions
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc index 77300dd2cf3..c6e421d763c 100644 --- a/sql/item_subselect.cc +++ b/sql/item_subselect.cc @@ -152,8 +152,8 @@ inline table_map Item_subselect::used_tables() const } Item_singlerow_subselect::Item_singlerow_subselect(THD *thd, - st_select_lex *select_lex): - Item_subselect(), value(0) + st_select_lex *select_lex) + :Item_subselect(), value(0) { DBUG_ENTER("Item_singlerow_subselect::Item_singlerow_subselect"); init(thd, select_lex, new select_singlerow_subselect(this)); @@ -163,6 +163,19 @@ Item_singlerow_subselect::Item_singlerow_subselect(THD *thd, DBUG_VOID_RETURN; } +Item_maxmin_subselect::Item_maxmin_subselect(THD *thd, + st_select_lex *select_lex, + bool max) + :Item_singlerow_subselect() +{ + DBUG_ENTER("Item_maxmin_subselect::Item_maxmin_subselect"); + init(thd, select_lex, new select_max_min_finder_subselect(this, max)); + max_columns= 1; + maybe_null= 1; + max_columns= 1; + DBUG_VOID_RETURN; +} + void Item_singlerow_subselect::reset() { null_value= 1; @@ -499,38 +512,50 @@ Item_in_subselect::single_value_transformer(JOIN *join, (func == &Item_bool_func2::gt_creator || func == &Item_bool_func2::lt_creator || func == &Item_bool_func2::ge_creator || - func == &Item_bool_func2::le_creator) && - !select_lex->group_list.elements && - !select_lex->with_sum_func) + func == &Item_bool_func2::le_creator)) { - Item *item; - subs_type type= substype(); - if (func == &Item_bool_func2::le_creator || - func == &Item_bool_func2::lt_creator) + Item *subs; + if (!select_lex->group_list.elements && + !select_lex->with_sum_func) { - /* - (ALL && (> || =>)) || (ANY && (< || =<)) - for ALL condition is inverted - */ - item= new Item_sum_max(*select_lex->ref_pointer_array); + Item *item; + subs_type type= substype(); + if (func == &Item_bool_func2::le_creator || + func == &Item_bool_func2::lt_creator) + { + /* + (ALL && (> || =>)) || (ANY && (< || =<)) + for ALL condition is inverted + */ + item= new Item_sum_max(*select_lex->ref_pointer_array); + } + else + { + /* + (ALL && (< || =<)) || (ANY && (> || =>)) + for ALL condition is inverted + */ + item= new Item_sum_min(*select_lex->ref_pointer_array); + } + *select_lex->ref_pointer_array= item; + select_lex->item_list.empty(); + select_lex->item_list.push_back(item); + + if (item->fix_fields(thd, join->tables_list, &item)) + { + DBUG_RETURN(ERROR); + } + subs= new Item_singlerow_subselect(thd, select_lex); } else { - /* - (ALL && (< || =<)) || (ANY && (> || =>)) - for ALL condition is inverted - */ - item= new Item_sum_min(*select_lex->ref_pointer_array); - } - *select_lex->ref_pointer_array= item; - select_lex->item_list.empty(); - select_lex->item_list.push_back(item); - - if (item->fix_fields(thd, join->tables_list, &item)) - { - DBUG_RETURN(ERROR); + // remove LIMIT placed by ALL/ANY subquery + select_lex->master_unit()->global_parameters->select_limit= + HA_POS_ERROR; + subs= new Item_maxmin_subselect(thd, select_lex, + (func == &Item_bool_func2::le_creator || + func == &Item_bool_func2::lt_creator)); } - // left expression belong to outer select SELECT_LEX *current= thd->lex.current_select, *up; thd->lex.current_select= up= current->return_after_parsing(); @@ -540,8 +565,7 @@ Item_in_subselect::single_value_transformer(JOIN *join, DBUG_RETURN(ERROR); } thd->lex.current_select= current; - substitution= (*func)(left_expr, - new Item_singlerow_subselect(thd, select_lex)); + substitution= (*func)(left_expr, subs); DBUG_RETURN(OK); } diff --git a/sql/item_subselect.h b/sql/item_subselect.h index 9cfa304bb47..d3aa8f59e49 100644 --- a/sql/item_subselect.h +++ b/sql/item_subselect.h @@ -130,6 +130,7 @@ public: max_length= item->max_length; decimals= item->decimals; } + Item_singlerow_subselect() :Item_subselect(), value(0), row (0) {} subs_type substype() { return SINGLEROW_SUBS; } @@ -153,6 +154,15 @@ public: friend class select_singlerow_subselect; }; +/* used in static ALL/ANY optimisation */ +class Item_maxmin_subselect: public Item_singlerow_subselect +{ +public: + Item_maxmin_subselect(THD *thd, st_select_lex *select_lex, bool max); + Item_maxmin_subselect(Item_maxmin_subselect *item) + :Item_singlerow_subselect(item) {} +}; + /* exists subselect */ class Item_exists_subselect :public Item_subselect diff --git a/sql/sql_class.cc b/sql/sql_class.cc index c233ffd422a..6f72d592b6f 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -986,6 +986,95 @@ bool select_singlerow_subselect::send_data(List<Item> &items) DBUG_RETURN(0); } +bool select_max_min_finder_subselect::send_data(List<Item> &items) +{ + DBUG_ENTER("select_max_min_finder_subselect::send_data"); + Item_singlerow_subselect *it= (Item_singlerow_subselect *)item; + List_iterator_fast<Item> li(items); + Item *val_item= li++; + if (it->assigned()) + { + cache->store(val_item); + if ((this->*op)()) + it->store(0, cache); + } + else + { + if (!cache) + { + cache= Item_cache::get_cache(val_item->result_type()); + switch (val_item->result_type()) + { + case REAL_RESULT: + op= &select_max_min_finder_subselect::cmp_real; + break; + case INT_RESULT: + op= &select_max_min_finder_subselect::cmp_int; + break; + case STRING_RESULT: + op= &select_max_min_finder_subselect::cmp_str; + break; + case ROW_RESULT: + // This case should never be choosen + DBUG_ASSERT(0); + op= 0; + } + } + cache->store(val_item); + it->store(0, cache); + } + it->assigned(1); + DBUG_RETURN(0); +} + +bool select_max_min_finder_subselect::cmp_real() +{ + Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); + double val1= cache->val(), val2= maxmin->val(); + if (fmax) + return (cache->null_value && !maxmin->null_value) || + (!cache->null_value && !maxmin->null_value && + val1 > val2); + else + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + val1 < val2); +} + +bool select_max_min_finder_subselect::cmp_int() +{ + Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); + longlong val1= cache->val_int(), val2= maxmin->val_int(); + if (fmax) + return (cache->null_value && !maxmin->null_value) || + (!cache->null_value && !maxmin->null_value && + val1 > val2); + else + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + val1 < val2); +} + +bool select_max_min_finder_subselect::cmp_str() +{ + String *val1, *val2, buf1, buf2; + Item *maxmin= ((Item_singlerow_subselect *)item)->el(0); + /* + as far as both operand is Item_cache buf1 & buf2 will not be used, + but added for safety + */ + val1= cache->val_str(&buf1); + val2= maxmin->val_str(&buf1); + if (fmax) + return (cache->null_value && !maxmin->null_value) || + (!cache->null_value && !maxmin->null_value && + sortcmp(val1, val2, cache->collation.collation) > 0) ; + else + return (maxmin->null_value && !cache->null_value) || + (!cache->null_value && !maxmin->null_value && + sortcmp(val1, val2, cache->collation.collation) < 0); +} + bool select_exists_subselect::send_data(List<Item> &items) { DBUG_ENTER("select_exists_subselect::send_data"); diff --git a/sql/sql_class.h b/sql/sql_class.h index f6336cb7dd9..0c17c7b2b49 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -920,6 +920,22 @@ public: bool send_data(List<Item> &items); }; +/* used in independent ALL/ANY optimisation */ +class select_max_min_finder_subselect :public select_subselect +{ + Item_cache *cache; + bool (select_max_min_finder_subselect::*op)(); + bool fmax; +public: + select_max_min_finder_subselect(Item_subselect *item, bool mx) + :select_subselect(item), cache(0), fmax(mx) + {} + bool send_data(List<Item> &items); + bool cmp_real(); + bool cmp_int(); + bool cmp_str(); +}; + /* EXISTS subselect interface class */ class select_exists_subselect :public select_subselect { |