From 629557ff13e28e3422dfa1c354c44ef2fd62e4d0 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 3 Sep 2009 18:03:46 +0300 Subject: Bug #46791: Assertion failed:(table->key_read==0),function unknown function,file sql_base.cc When uncacheable queries are written to a temp table the optimizer must preserve the original JOIN structure, because it is re-using the JOIN structure to read from the resulting temporary table. This was done only for uncacheable sub-queries. But top level queries can also benefit from this mechanism, specially if they're using index access and need a reset. Fixed by not limiting the saving of JOIN structure to subqueries exclusively. Added a new test file to extend the existing (large) subquery.test. --- sql/sql_select.cc | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index b670e6e3637..9d5e67c9532 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1474,12 +1474,8 @@ JOIN::optimize() } } - /* - If this join belongs to an uncacheable subquery save - the original join - */ - if (select_lex->uncacheable && !is_top_level_join() && - init_save_join_tab()) + /* If this join belongs to an uncacheable query save the original join */ + if (select_lex->uncacheable && init_save_join_tab()) DBUG_RETURN(-1); /* purecov: inspected */ } -- cgit v1.2.1 From 643fbe4234a06e51746c8912223652a3b41fe133 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Fri, 4 Sep 2009 12:20:53 +0500 Subject: Bug#45989 memory leak after explain encounters an error in the query Memory allocated in TMP_TABLE_PARAM::copy_field is not cleaned up. The fix is to clean up TMP_TABLE_PARAM::copy_field array in JOIN::destroy. mysql-test/r/explain.result: test result mysql-test/t/explain.test: test case sql/sql_select.cc: Memory allocated in TMP_TABLE_PARAM::copy_field is not cleaned up. The fix is to clean up TMP_TABLE_PARAM::copy_field array in JOIN::destroy. --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index ff179c432a8..b670e6e3637 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2176,7 +2176,7 @@ JOIN::destroy() } } tmp_join->tmp_join= 0; - tmp_table_param.copy_field=0; + tmp_table_param.cleanup(); DBUG_RETURN(tmp_join->destroy()); } cond_equal= 0; -- cgit v1.2.1 From 505346028f975d26f1353c46bdb3db618b1e306c Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Sun, 6 Sep 2009 00:42:17 +0400 Subject: Bug #46159: simple query that never returns The external 'for' loop in remove_dup_with_compare() handled HA_ERR_RECORD_DELETED by just starting over without advancing to the next record which caused an infinite loop. This condition could be triggered on certain data by a SELECT query containing DISTINCT, GROUP BY and HAVING clauses. Fixed remove_dup_with_compare() so that we always advance to the next record when receiving HA_ERR_RECORD_DELETED from rnd_next(). mysql-test/r/distinct.result: Added a test case for bug #46159. mysql-test/t/distinct.test: Added a test case for bug #46159. sql/sql_select.cc: Fixed remove_dup_with_compare() so that we always advance to the next record when receiving HA_ERR_RECORD_DELETED from rnd_next(). --- sql/sql_select.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 5cb0de1ba5c..a02430446d1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -13665,7 +13665,10 @@ static int remove_dup_with_compare(THD *thd, TABLE *table, Field **first_field, if (error) { if (error == HA_ERR_RECORD_DELETED) - continue; + { + error= file->rnd_next(record); + continue; + } if (error == HA_ERR_END_OF_FILE) break; goto err; -- cgit v1.2.1 From e5888b16afcef42e8127a815cc5a95abc283c6d9 Mon Sep 17 00:00:00 2001 From: Staale Smedseng Date: Thu, 17 Sep 2009 17:10:30 +0200 Subject: Bug #43414 Parenthesis (and other) warnings compiling MySQL with gcc 4.3.2 This is the fifth patch cleaning up more GCC warnings about variables used before initialized using the new macro UNINIT_VAR(). --- sql/sql_select.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9d5e67c9532..84b5b61c941 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10480,9 +10480,8 @@ do_select(JOIN *join,List *fields,TABLE *table,Procedure *procedure) { int rc= 0; enum_nested_loop_state error= NESTED_LOOP_OK; - JOIN_TAB *join_tab; + JOIN_TAB *UNINIT_VAR(join_tab); DBUG_ENTER("do_select"); - LINT_INIT(join_tab); join->procedure=procedure; join->tmp_table= table; /* Save for easy recursion */ -- cgit v1.2.1 From 5dda6c18cdb6b549681f76b6158baa3afd2816bb Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 18 Sep 2009 12:34:08 +0300 Subject: Bug #47106: Crash / segfault on adding EXPLAIN to a non-crashing query The fix for bug 46749 removed the check for OUTER_REF_TABLE_BIT and substituted it for a check on the presence of Item_ident::depended_from. Removing it altogether was wrong : OUTER_REF_TABLE_BIT should still be checked in addition to depended_from (because it's not set in all cases and doesn't contradict to the check of depended_from). Fixed by returning the old condition back as a compliment to the new one. --- sql/sql_select.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 84b5b61c941..76d6833de5c 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3216,12 +3216,12 @@ add_key_equal_fields(KEY_FIELD **key_fields, uint and_level, @retval FALSE it's something else */ -inline static bool +static bool is_local_field (Item *field) { - field= field->real_item(); - return field->type() == Item::FIELD_ITEM && - !((Item_field *)field)->depended_from; + return field->real_item()->type() == Item::FIELD_ITEM + && !(field->used_tables() & OUTER_REF_TABLE_BIT) + && !((Item_field *)field->real_item())->depended_from; } -- cgit v1.2.1 From beb519e3caa387b715a6093251ec0b7e5ce61da0 Mon Sep 17 00:00:00 2001 From: Sergey Glukhov Date: Wed, 23 Sep 2009 13:40:33 +0500 Subject: Bug#45989 memory leak after explain encounters an error in the query the fix is reverted from 5.1, mysql-pe as unnecessary(no valgrind warnings there). sql/sql_select.cc: the fix is reverted from 5.1, mysql-pe as unnecessary(no valgrind warnings there). --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8b1e0ae365b..1ff068c8881 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2248,7 +2248,7 @@ JOIN::destroy() tab->cleanup(); } tmp_join->tmp_join= 0; - tmp_table_param.cleanup(); + tmp_table_param.copy_field= 0; DBUG_RETURN(tmp_join->destroy()); } cond_equal= 0; -- cgit v1.2.1 From 1a48dd4e2bf0c6353bbf76b1f9b768620e0aa090 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Wed, 7 Oct 2009 18:03:42 +0300 Subject: Bug #43029: FORCE INDEX FOR ORDER BY is ignored when join buffering is used FORCE INDEX FOR ORDER BY now prevents the optimizer from using join buffering. As a result the optimizer can use indexed access on the first table and doesn't need to sort the complete resultset at the end of the statement. --- sql/sql_select.cc | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3f1432914a0..9dacb2c2ce4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1231,13 +1231,22 @@ JOIN::optimize() (!group_list && tmp_table_param.sum_func_count)) order=0; - // Can't use sort on head table if using row cache + // Can't use sort on head table if using join buffering if (full_join) { - if (group_list) - simple_group=0; - if (order) - simple_order=0; + TABLE *stable= (sort_by_table == (TABLE *) 1 ? + join_tab[const_tables].table : sort_by_table); + /* + FORCE INDEX FOR ORDER BY can be used to prevent join buffering when + sorting on the first table. + */ + if (!stable || !stable->force_index_order) + { + if (group_list) + simple_group= 0; + if (order) + simple_order= 0; + } } /* -- cgit v1.2.1 From 6da93b223b4b929402b432f90b2585d38f2f1e5a Mon Sep 17 00:00:00 2001 From: Jorgen Loland Date: Wed, 14 Oct 2009 10:46:50 +0200 Subject: Bug#47280 - strange results from count(*) with order by multiple columns without where/group Simple SELECT with implicit grouping used to return many rows if the query was ordered by the aggregated column in the SELECT list. This was incorrect because queries with implicit grouping should only return a single record. The problem was that when JOIN:exec() decided if execution needed to handle grouping, it was assumed that sum_func_count==0 meant that there were no aggregate functions in the query. This assumption was not correct in JOIN::exec() because the aggregate functions might have been optimized away during JOIN::optimize(). The reason why queries without ordering behaved correctly was that sum_func_count is only recalculated if the optimizer chooses to use temporary tables (which it does in the ordered case). Hence, non-ordered queries were correctly treated as grouped. The fix for this bug was to remove the assumption that sum_func_count==0 means that there is no need for grouping. This was done by introducing variable "bool implicit_grouping" in the JOIN object. mysql-test/r/func_group.result: Add test for BUG#47280 mysql-test/t/func_group.test: Add test for BUG#47280 sql/opt_sum.cc: Improve comment for opt_sum_query() sql/sql_class.h: Add comment for variables in TMP_TABLE_PARAM sql/sql_select.cc: Introduce and use variable implicit_grouping instead of (!group_list && sum_func_count) in places that need to test if grouping is required. Also added comments for: optimization of aggregate fields for implicitly grouped queries (JOIN::optimize) and choice of end_select method (JOIN::execute) sql/sql_select.h: Add variable implicit_grouping, which will be TRUE for queries that contain aggregate functions but no GROUP BY clause. Also added comment to sort_and_group variable. --- sql/sql_select.cc | 27 ++++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 9dacb2c2ce4..02e52e0c518 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -644,8 +644,11 @@ JOIN::prepare(Item ***rref_pointer_array, this->group= group_list != 0; unit= unit_arg; + if (tmp_table_param.sum_func_count && !group_list) + implicit_grouping= TRUE; + #ifdef RESTRICTED_GROUP - if (sum_func_count && !group_list && (func_count || field_count)) + if (implicit_grouping) { my_message(ER_WRONG_SUM_SELECT,ER(ER_WRONG_SUM_SELECT),MYF(0)); goto err; @@ -881,15 +884,23 @@ JOIN::optimize() } #endif - /* Optimize count(*), min() and max() */ - if (tables_list && tmp_table_param.sum_func_count && ! group_list) + /* + Try to optimize count(*), min() and max() to const fields if + there is implicit grouping (aggregate functions but no + group_list). In this case, the result set shall only contain one + row. + */ + if (tables_list && implicit_grouping) { int res; /* opt_sum_query() returns HA_ERR_KEY_NOT_FOUND if no rows match to the WHERE conditions, - or 1 if all items were resolved, + or 1 if all items were resolved (optimized away), or 0, or an error number HA_ERR_... + + If all items were resolved by opt_sum_query, there is no need to + open any tables. */ if ((res=opt_sum_query(select_lex->leaf_tables, all_fields, conds))) { @@ -2024,7 +2035,7 @@ JOIN::exec() count_field_types(select_lex, &curr_join->tmp_table_param, *curr_all_fields, 0); - if (curr_join->group || curr_join->tmp_table_param.sum_func_count || + if (curr_join->group || curr_join->implicit_grouping || (procedure && (procedure->flags & PROC_GROUP))) { if (make_group_fields(this, curr_join)) @@ -10811,6 +10822,12 @@ Next_select_func setup_end_select_func(JOIN *join) } else { + /* + Choose method for presenting result to user. Use end_send_group + if the query requires grouping (has a GROUP BY clause and/or one or + more aggregate functions). Use end_send if the query should not + be grouped. + */ if ((join->sort_and_group || (join->procedure && join->procedure->flags & PROC_GROUP)) && !tmp_tbl->precomputed_group_by) -- cgit v1.2.1 From bf14598c9903067474a7cdf1c49bca9f52d0c55a Mon Sep 17 00:00:00 2001 From: Jorgen Loland Date: Wed, 14 Oct 2009 18:20:01 +0200 Subject: Followup patch for BUG#47280 Temporary tables may set join->group to 0 even though there is grouping. Also need to test if sum_func_count>0 when JOIN::exec() decides whether to present results in a grouped manner. sql/sql_select.cc: Temporary tables may set join->group to 0 even though there is grouping. Also need to test if sum_func_count>0 when JOIN::exec() decides whether to present results in a grouped manner. --- sql/sql_select.cc | 1 + 1 file changed, 1 insertion(+) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 02e52e0c518..c5e0bce498d 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2036,6 +2036,7 @@ JOIN::exec() *curr_all_fields, 0); if (curr_join->group || curr_join->implicit_grouping || + curr_join->tmp_table_param.sum_func_count || (procedure && (procedure->flags & PROC_GROUP))) { if (make_group_fields(this, curr_join)) -- cgit v1.2.1 From 17ed6b9abda235daf41eb62512116384c1e06e25 Mon Sep 17 00:00:00 2001 From: Ramil Kalimullin Date: Wed, 21 Oct 2009 14:04:08 +0500 Subject: Fix for bug#47019: Assertion failed: 0, file .\rt_mbr.c, line 138 when forcing a spatial index Problem: "Spatial indexes can be involved in the search for queries that use a function such as MBRContains() or MBRWithin() in the WHERE clause". Using spatial indexes for JOINs with =, <=> etc. predicates is incorrect. Fix: disable spatial indexes for such queries. mysql-test/r/select.result: Fix for bug#47019: Assertion failed: 0, file .\rt_mbr.c, line 138 when forcing a spatial index - test result. mysql-test/t/select.test: Fix for bug#47019: Assertion failed: 0, file .\rt_mbr.c, line 138 when forcing a spatial index - test case. sql/sql_select.cc: Fix for bug#47019: Assertion failed: 0, file .\rt_mbr.c, line 138 when forcing a spatial index - disable spatial indexes for queries which use non-spatial conditions (e.g. NATURAL JOINs). --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 76d6833de5c..3bf67299d58 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -3447,7 +3447,7 @@ add_key_part(DYNAMIC_ARRAY *keyuse_array,KEY_FIELD *key_field) { if (!(form->keys_in_use_for_query.is_set(key))) continue; - if (form->key_info[key].flags & HA_FULLTEXT) + if (form->key_info[key].flags & (HA_FULLTEXT | HA_SPATIAL)) continue; // ToDo: ft-keys in non-ft queries. SerG uint key_parts= (uint) form->key_info[key].key_parts; -- cgit v1.2.1 From ac37324843b97fc69c307f8bab52af69c81c1245 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Thu, 29 Oct 2009 17:24:29 +0200 Subject: Bug #42116 : Mysql crash on specific query Queries with nested outer joins may lead to crashes or bad results because an internal data structure is not handled correctly. The optimizer uses bitmaps of nested JOINs to determine if certain table can be placed at a certain place in the JOIN order. It does maintain a bitmap describing in which JOINs last placed table is nested. When it puts a table it makes sure the bit of every JOIN that contains the table in question is set (because JOINs can be nested). It does that by recursively setting the bit for the next enclosing JOIN when this is the first table in the JOIN and recursively resetting the bit if it's the last table in the JOIN. When it removes a table from the join order it should do the opposite : recursively unset the bit if it's the only remaining table in this join and and recursively set the bit if it's removing the last table of a JOIN. There was an error in how the bits was set for the upper levels : when removing a table it was setting the bit for all the enclosing nested JOINs even if there were more tables left in the current JOIN (which practically means that the upper nested JOINs were not affected). Fixed by stopping the recursion at the relevant level. mysql-test/r/join.result: Bug #42116: test case mysql-test/t/join.test: Bug #42116: test case sql/sql_select.cc: Bug #41116: don't go up and set the bits if more tables in at the current JOIN level --- sql/sql_select.cc | 3 +++ 1 file changed, 3 insertions(+) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 3bf67299d58..8136c6f7635 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8640,7 +8640,10 @@ static void restore_prev_nj_state(JOIN_TAB *last) join->cur_embedding_map&= ~last_emb->nested_join->nj_map; else if (last_emb->nested_join->join_list.elements-1 == last_emb->nested_join->counter) + { join->cur_embedding_map|= last_emb->nested_join->nj_map; + break; + } else break; last_emb= last_emb->embedding; -- cgit v1.2.1 From 851e250953e531c2c5189dff0d7202cb79acf5d6 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 30 Oct 2009 11:40:44 +0200 Subject: Bug #48293: crash with procedure analyse, view with > 10 columns, having clause... The fix for bug 46184 was not very complete. It was not covering views using temporary tables and multiple tables in a FROM clause. Fixed by reverting the fix for 46184 and making a more general check that is checking at the right execution stage and for all of the non-supported cases. Now PROCEDURE ANALYZE on non-top level SELECT is also forbidden. Updated the analyse.test and subselect.test accordingly. --- sql/sql_select.cc | 12 ++++++++++++ 1 file changed, 12 insertions(+) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 8136c6f7635..c425d9a988e 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -622,6 +622,18 @@ JOIN::prepare(Item ***rref_pointer_array, MYF(0)); /* purecov: inspected */ goto err; /* purecov: inspected */ } + if (thd->lex->derived_tables) + { + my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", + thd->lex->derived_tables & DERIVED_VIEW ? + "view" : "subquery"); + goto err; + } + if (thd->lex->sql_command != SQLCOM_SELECT) + { + my_error(ER_WRONG_USAGE, MYF(0), "PROCEDURE", "non-SELECT"); + goto err; + } } if (!procedure && result && result->prepare(fields_list, unit_arg)) -- cgit v1.2.1 From 9d96cd6dcb3f171cbbe93c0f7061ce132a9087a7 Mon Sep 17 00:00:00 2001 From: Georgi Kodinov Date: Fri, 30 Oct 2009 15:15:43 +0200 Subject: Bug #48291 : crash with row() operator,select into @var, and subquery returning multiple rows Error handling was missing when handling subqueires in WHERE and when assigning a SELECT result to a @variable. This caused crash(es). Fixed by adding error handling code to both the WHERE condition evaluation and to assignment to an @variable. --- sql/sql_select.cc | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index c425d9a988e..d5c2b93dfb4 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -10822,6 +10822,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, bool not_used_in_distinct=join_tab->not_used_in_distinct; ha_rows found_records=join->found_records; COND *select_cond= join_tab->select_cond; + bool select_cond_result= TRUE; if (error > 0 || (*report_error)) // Fatal error return NESTED_LOOP_ERROR; @@ -10833,7 +10834,17 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, return NESTED_LOOP_KILLED; /* purecov: inspected */ } DBUG_PRINT("info", ("select cond 0x%lx", (ulong)select_cond)); - if (!select_cond || select_cond->val_int()) + + if (select_cond) + { + select_cond_result= test(select_cond->val_int()); + + /* check for errors evaluating the condition */ + if (join->thd->net.report_error) + return NESTED_LOOP_ERROR; + } + + if (!select_cond || select_cond_result) { /* There is no select condition or the attached pushed down -- cgit v1.2.1 From b67cdaa351122ca0d8badd2f8fb4ec9085c58933 Mon Sep 17 00:00:00 2001 From: Alexey Kopytov Date: Fri, 30 Oct 2009 18:54:53 +0300 Subject: Bug #48131: crash group by with rollup, distinct, filesort, with temporary tables There were two problems the test case from this bug was triggering: 1. JOIN::rollup_init() was supposed to wrap all constant Items into another object for queries with the WITH ROLLUP modifier to ensure they are never considered as constants and therefore are written into temporary tables if the optimizer chooses to employ them for DISTINCT/GROUP BY handling. However, JOIN::rollup_init() was called before make_join_statistics(), so Items corresponding to fields in const tables could not be handled as intended, which was causing all kinds of problems later in the query execution. In particular, create_tmp_table() assumed all constant items except "hidden" ones to be removed earlier by remove_const() which led to improperly initialized Field objects for the temporary table being created. This is what was causing crashes and valgrind errors in storage engines. 2. Even when the above problem had been fixed, the query from the test case produced incorrect results due to some DISTINCT/GROUP BY optimizations being performed by the optimizer that are inapplicable in the WITH ROLLUP case. Fixed by disabling inapplicable DISTINCT/GROUP BY optimizations when the WITH ROLLUP modifier is present, and splitting the const-wrapping part of JOIN::rollup_init() into a separate method which is now invoked after make_join_statistics() when the const tables are already known. mysql-test/r/olap.result: Added a test case for bug #48131. mysql-test/t/olap.test: Added a test case for bug #48131. sql/sql_select.cc: 1. Disabled inapplicable DISTINCT/GROUP BY optimizations when the WITH ROLLUP modifier is present. 2. Split the const-wrapping part of JOIN::rollup_init() into a separate method. sql/sql_select.h: Added rollup_process_const_fields() declaration. --- sql/sql_select.cc | 92 ++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 64 insertions(+), 28 deletions(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 76d6833de5c..11c7331b276 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -916,6 +916,12 @@ JOIN::optimize() DBUG_RETURN(1); } + if (select_lex->olap == ROLLUP_TYPE && rollup_process_const_fields()) + { + DBUG_PRINT("error", ("Error: rollup_process_fields() failed")); + DBUG_RETURN(1); + } + /* Remove distinct if only const tables */ select_distinct= select_distinct && (const_tables != tables); thd_proc_info(thd, "preparing"); @@ -1043,7 +1049,7 @@ JOIN::optimize() join_tab[const_tables].select->quick->get_type() != QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX)) { - if (group_list && + if (group_list && rollup.state == ROLLUP::STATE_NONE && list_contains_unique_index(join_tab[const_tables].table, find_field_in_order_list, (void *) group_list)) @@ -1081,7 +1087,8 @@ JOIN::optimize() if (! hidden_group_fields && rollup.state == ROLLUP::STATE_NONE) select_distinct=0; } - else if (select_distinct && tables - const_tables == 1) + else if (select_distinct && tables - const_tables == 1 && + rollup.state == ROLLUP::STATE_NONE) { /* We are only using one table. In this case we change DISTINCT to a @@ -9858,6 +9865,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List &fields, for (; cur_group ; cur_group= cur_group->next, key_part_info++) { Field *field=(*cur_group->item)->get_tmp_table_field(); + DBUG_ASSERT(field->table == table); bool maybe_null=(*cur_group->item)->maybe_null; key_part_info->null_bit=0; key_part_info->field= field; @@ -14992,32 +15000,7 @@ bool JOIN::rollup_init() { item->maybe_null= 1; found_in_group= 1; - if (item->const_item()) - { - /* - For ROLLUP queries each constant item referenced in GROUP BY list - is wrapped up into an Item_func object yielding the same value - as the constant item. The objects of the wrapper class are never - considered as constant items and besides they inherit all - properties of the Item_result_field class. - This wrapping allows us to ensure writing constant items - into temporary tables whenever the result of the ROLLUP - operation has to be written into a temporary table, e.g. when - ROLLUP is used together with DISTINCT in the SELECT list. - Usually when creating temporary tables for a intermidiate - result we do not include fields for constant expressions. - */ - Item* new_item= new Item_func_rollup_const(item); - if (!new_item) - return 1; - new_item->fix_fields(thd, (Item **) 0); - thd->change_item_tree(it.ref(), new_item); - for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) - { - if (*tmp->item == item) - thd->change_item_tree(tmp->item, new_item); - } - } + break; } } if (item->type() == Item::FUNC_ITEM && !found_in_group) @@ -15036,6 +15019,59 @@ bool JOIN::rollup_init() } return 0; } + +/** + Wrap all constant Items in GROUP BY list. + + For ROLLUP queries each constant item referenced in GROUP BY list + is wrapped up into an Item_func object yielding the same value + as the constant item. The objects of the wrapper class are never + considered as constant items and besides they inherit all + properties of the Item_result_field class. + This wrapping allows us to ensure writing constant items + into temporary tables whenever the result of the ROLLUP + operation has to be written into a temporary table, e.g. when + ROLLUP is used together with DISTINCT in the SELECT list. + Usually when creating temporary tables for a intermidiate + result we do not include fields for constant expressions. + + @retval + 0 if ok + @retval + 1 on error +*/ + +bool JOIN::rollup_process_const_fields() +{ + ORDER *group_tmp; + Item *item; + List_iterator it(all_fields); + + for (group_tmp= group_list; group_tmp; group_tmp= group_tmp->next) + { + if (!(*group_tmp->item)->const_item()) + continue; + while ((item= it++)) + { + if (*group_tmp->item == item) + { + Item* new_item= new Item_func_rollup_const(item); + if (!new_item) + return 1; + new_item->fix_fields(thd, (Item **) 0); + thd->change_item_tree(it.ref(), new_item); + for (ORDER *tmp= group_tmp; tmp; tmp= tmp->next) + { + if (*tmp->item == item) + thd->change_item_tree(tmp->item, new_item); + } + break; + } + } + it.rewind(); + } + return 0; +} /* -- cgit v1.2.1 From 1ca80ed19e14d8d5837fa900ad75ec1a7a7856e1 Mon Sep 17 00:00:00 2001 From: Davi Arnaut Date: Mon, 2 Nov 2009 09:21:39 -0200 Subject: Bug#48370: Absolutely wrong calculations with GROUP BY and decimal fields when using IF Bug#45261: Crash, stored procedure + decimal Revert fix for Bug#45261 due to unforeseen bugs. --- sql/sql_select.cc | 41 ++++++++++++++++++++++++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 27ffb491173..854dd296039 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -9433,8 +9433,47 @@ static Field *create_tmp_field_from_item(THD *thd, Item *item, TABLE *table, new_field->set_derivation(item->collation.derivation); break; case DECIMAL_RESULT: - new_field= Field_new_decimal::new_decimal_field(item); + { + uint8 dec= item->decimals; + uint8 intg= ((Item_decimal *) item)->decimal_precision() - dec; + uint32 len= item->max_length; + + /* + Trying to put too many digits overall in a DECIMAL(prec,dec) + will always throw a warning. We must limit dec to + DECIMAL_MAX_SCALE however to prevent an assert() later. + */ + + if (dec > 0) + { + signed int overflow; + + dec= min(dec, DECIMAL_MAX_SCALE); + + /* + If the value still overflows the field with the corrected dec, + we'll throw out decimals rather than integers. This is still + bad and of course throws a truncation warning. + +1: for decimal point + */ + + const int required_length= + my_decimal_precision_to_length(intg + dec, dec, + item->unsigned_flag); + + overflow= required_length - len; + + if (overflow > 0) + dec= max(0, dec - overflow); // too long, discard fract + else + /* Corrected value fits. */ + len= required_length; + } + + new_field= new Field_new_decimal(len, maybe_null, item->name, + dec, item->unsigned_flag); break; + } case ROW_RESULT: default: // This case should never be choosen -- cgit v1.2.1 From 06c9d62a9f72c1554b3619f10388092da4ee9c04 Mon Sep 17 00:00:00 2001 From: Konstantin Osipov Date: Tue, 3 Nov 2009 19:58:54 +0300 Subject: A fix and a test case for Bug#41756 "Strange error messages about locks from InnoDB". In JT_EQ_REF (join_read_key()) access method, don't try to unlock rows in the handler, unless certain that a) they were locked b) they are not used. Unlocking of rows is done by the logic of the nested join loop, and is unaware of the possible caching that the access method may have. This could lead to double unlocking, when a row was unlocked first after reading into the cache, and then when taken from cache, as well as to unlocking of rows which were actually used (but taken from cache). Delegate part of the unlocking logic to the access method, and in JT_EQ_REF count how many times a record was actually used in the join. Unlock it only if it's usage count is 0. Implemented review comments. mysql-test/r/bug41756.result: Add result file (Bug#41756) mysql-test/t/bug41756-master.opt: Use --innodb-locks-unsafe-for-binlog, as in 5.0 just using read_committed isolation is not sufficient to reproduce the bug. mysql-test/t/bug41756.test: Add a test file (Bug#41756) sql/item_subselect.cc: Complete struct READ_RECORD initialization with a new member to unlock records. sql/records.cc: Extend READ_RECORD API with a method to unlock read records. sql/sql_select.cc: In JT_EQ_REF (join_read_key()) access method, don't try to unlock rows in the handler, unless certain that a) they were locked b) they are not used. sql/sql_select.h: Add members to TABLE_REF to count TABLE_REF buffer usage count. sql/structs.h: Update declarations. --- sql/sql_select.cc | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 59 insertions(+), 2 deletions(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0014504a52f..51794c1f158 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -140,6 +140,7 @@ static int join_read_const_table(JOIN_TAB *tab, POSITION *pos); static int join_read_system(JOIN_TAB *tab); static int join_read_const(JOIN_TAB *tab); static int join_read_key(JOIN_TAB *tab); +static void join_read_key_unlock_row(st_join_table *tab); static int join_read_always_key(JOIN_TAB *tab); static int join_read_last_key(JOIN_TAB *tab); static int join_no_more_records(READ_RECORD *info); @@ -5376,7 +5377,9 @@ static bool create_ref_for_key(JOIN *join, JOIN_TAB *j, KEYUSE *org_keyuse, } j->ref.key_buff2=j->ref.key_buff+ALIGN_SIZE(length); j->ref.key_err=1; + j->ref.has_record= FALSE; j->ref.null_rejecting= 0; + j->ref.use_count= 0; keyuse=org_keyuse; store_key **ref_key= j->ref.key_copy; @@ -6176,6 +6179,20 @@ make_join_select(JOIN *join,SQL_SELECT *select,COND *cond) DBUG_RETURN(0); } + +/** + The default implementation of unlock-row method of READ_RECORD, + used in all access methods. +*/ + +void rr_unlock_row(st_join_table *tab) +{ + READ_RECORD *info= &tab->read_record; + info->file->unlock_row(); +} + + + static void make_join_readinfo(JOIN *join, ulonglong options) { @@ -6191,6 +6208,7 @@ make_join_readinfo(JOIN *join, ulonglong options) TABLE *table=tab->table; tab->read_record.table= table; tab->read_record.file=table->file; + tab->read_record.unlock_row= rr_unlock_row; tab->next_select=sub_select; /* normal select */ /* @@ -6234,6 +6252,7 @@ make_join_readinfo(JOIN *join, ulonglong options) delete tab->quick; tab->quick=0; tab->read_first_record= join_read_key; + tab->read_record.unlock_row= join_read_key_unlock_row; tab->read_record.read_record= join_no_more_records; if (table->used_keys.is_set(tab->ref.key) && !table->no_keyread) @@ -10936,7 +10955,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, return NESTED_LOOP_NO_MORE_ROWS; } else - join_tab->read_record.file->unlock_row(); + join_tab->read_record.unlock_row(join_tab); } else { @@ -10946,7 +10965,7 @@ evaluate_join_record(JOIN *join, JOIN_TAB *join_tab, */ join->examined_rows++; join->thd->row_count++; - join_tab->read_record.file->unlock_row(); + join_tab->read_record.unlock_row(join_tab); } return NESTED_LOOP_OK; } @@ -11299,17 +11318,55 @@ join_read_key(JOIN_TAB *tab) table->status=STATUS_NOT_FOUND; return -1; } + /* + Moving away from the current record. Unlock the row + in the handler if it did not match the partial WHERE. + */ + if (tab->ref.has_record && tab->ref.use_count == 0) + { + tab->read_record.file->unlock_row(); + tab->ref.has_record= FALSE; + } + error=table->file->index_read(table->record[0], tab->ref.key_buff, tab->ref.key_length,HA_READ_KEY_EXACT); if (error && error != HA_ERR_KEY_NOT_FOUND) return report_error(table, error); + + if (! error) + { + tab->ref.has_record= TRUE; + tab->ref.use_count= 1; + } + } + else if (table->status == 0) + { + DBUG_ASSERT(tab->ref.has_record); + tab->ref.use_count++; } table->null_row=0; return table->status ? -1 : 0; } +/** + Since join_read_key may buffer a record, do not unlock + it if it was not used in this invocation of join_read_key(). + Only count locks, thus remembering if the record was left unused, + and unlock already when pruning the current value of + TABLE_REF buffer. + @sa join_read_key() +*/ + +static void +join_read_key_unlock_row(st_join_table *tab) +{ + DBUG_ASSERT(tab->ref.use_count); + if (tab->ref.use_count) + tab->ref.use_count--; +} + /* ref access method implementation: "read_first" function -- cgit v1.2.1 From efa74c7dd46897e8fef76e3aab35fc7262267823 Mon Sep 17 00:00:00 2001 From: unknown Date: Mon, 16 Nov 2009 21:54:33 +0100 Subject: Corrected a line from the patch for table elimination (WL#17) to fix a problem with the test case for bug#42116. Re-commit of Igor's fix due to re-commit of MySQL 5.1.41 merge. --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 30a91e882fe..70e520b3e4a 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -8937,7 +8937,7 @@ static uint reset_nj_counters(JOIN *join, List *join_list) // ~join->eliminated_tables); nested_join->n_tables= reset_nj_counters(join, &nested_join->join_list); } - if (table->table && (table->table->map & ~join->eliminated_tables)) + if (!table->table || (table->table->map & ~join->eliminated_tables)) n++; } DBUG_RETURN(n); -- cgit v1.2.1 From 84911a9fd0a31a03a1692040d21ecbe0198a01d7 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 27 Nov 2009 14:20:59 +0100 Subject: After-merge fixes for MySQL 5.1.41 merge into MariaDB: more fixes for Buildbot problems. mysql-test/mysql-test-run.pl: Manually apply similar patch to the one in Bug#47983. mysql-test/suite/rpl/r/rpl_temporary_errors.result: Fix wrong failure with warning in error log due to per-test suppressions not being active during server shutdown. mysql-test/suite/rpl/t/rpl_temporary_errors.test: Fix wrong failure with warning in error log due to per-test suppressions not being active during server shutdown. sql/sql_select.cc: Manually cherry-pick fix for Bug#45989. For some reason, that fix was reverted in MySQL 5.1, even though it is necessary to plug the memory leak. --- sql/sql_select.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sql/sql_select.cc') diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 70e520b3e4a..829db08dfbb 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -2311,7 +2311,7 @@ JOIN::destroy() tab->cleanup(); } tmp_join->tmp_join= 0; - tmp_table_param.copy_field= 0; + tmp_table_param.cleanup(); DBUG_RETURN(tmp_join->destroy()); } cond_equal= 0; -- cgit v1.2.1