From: Date: January 18 2007 9:31am Subject: bk commit into 5.0 tree (ted:1.2382) BUG#25219 List-Archive: http://lists.mysql.com/commits/18313 X-Bug: 25219 Message-Id: <200701180831.l0I8VKqq026798@localhost.localdomain> Below is the list of changes that have just been committed into a local 5.0 repository of ted. When ted does a push these changes will be propagated to the main repository and, within 24 hours after the push, to the public repository. For information on how to access the public repository see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html ChangeSet@stripped, 2007-01-18 11:31:14+03:00, ted@stripped +1 -0 BUG#25219: SELECT with subqueries causes MySQL server crash fix: make_cond_for_table() cleaned up; hacks to workaround bug with quick selects avoided; see rejects against current test results attached to the bug page sql/sql_select.cc@stripped, 2007-01-18 11:31:12+03:00, ted@stripped +60 -63 make_cond_for_table() now looks a little bit more manageable and hopefully consistent # This is a BitKeeper patch. What follows are the unified diffs for the # set of deltas contained in the patch. The rest of the patch, the part # that BitKeeper cares about, is below these diffs. # User: ted # Host: ted.mysql.internal # Root: /usr/local/src/mysql/bug25219/50 --- 1.478/sql/sql_select.cc 2007-01-18 11:31:20 +03:00 +++ 1.479/sql/sql_select.cc 2007-01-18 11:31:20 +03:00 @@ -5468,8 +5468,9 @@ &thd->lex->unit) // not upper level SELECT join->const_table_map|=RAND_TABLE_BIT; { // Check const tables - COND *const_cond= - make_cond_for_table(cond, + COND *const_cond= (COND*) 0; + if (join->const_table_map) + const_cond= make_cond_for_table(cond, join->const_table_map, (table_map) 0); DBUG_EXECUTE("where",print_where(const_cond,"constants");); @@ -5536,31 +5537,7 @@ tmp= NULL; if (cond) tmp= make_cond_for_table(cond,used_tables,current_map); - if (cond && !tmp && tab->quick) - { // Outer join - if (tab->type != JT_ALL) - { - /* - Don't use the quick method - We come here in the case where we have 'key=constant' and - the test is removed by make_cond_for_table() - */ - delete tab->quick; - tab->quick= 0; - } - else - { - /* - Hack to handle the case where we only refer to a table - in the ON part of an OUTER JOIN. In this case we want the code - below to check if we should use 'quick' instead. - */ - DBUG_PRINT("info", ("Item_int")); - tmp= new Item_int((longlong) 1,1); // Always true - DBUG_PRINT("info", ("Item_int 0x%lx", (ulong)tmp)); - } - } if (tmp || !cond) { DBUG_EXECUTE("where",print_where(tmp,tab->table->alias);); @@ -11591,16 +11568,20 @@ static COND * make_cond_for_table(COND *cond, table_map tables, table_map used_table) { - if (used_table && !(cond->used_tables() & used_table)) - return (COND*) 0; // Already checked - if (cond->type() == Item::COND_ITEM) - { + COND *ret = (COND*) 0; + table_map used_tables = cond->used_tables(); + + if (used_table && used_tables && !(used_tables & used_table)) + return ret; // Already checked + + switch (cond->type()) { + case Item::COND_ITEM: if (((Item_cond*) cond)->functype() == Item_func::COND_AND_FUNC) { /* Create new top level AND item */ Item_cond_and *new_cond=new Item_cond_and; if (!new_cond) - return (COND*) 0; // OOM /* purecov: inspected */ + return ret; // OOM /* purecov: inspected */ List_iterator li(*((Item_cond*) cond)->argument_list()); Item *item; while ((item=li++)) @@ -11611,9 +11592,10 @@ } switch (new_cond->argument_list()->elements) { case 0: - return (COND*) 0; // Always true + break; // Always true case 1: - return new_cond->argument_list()->head(); + ret = new_cond->argument_list()->head(); + break; default: /* Item_cond_and do not need fix_fields for execution, its parameters @@ -11623,21 +11605,21 @@ new_cond->used_tables_cache= ((Item_cond_and*) cond)->used_tables_cache & tables; - return new_cond; + ret= new_cond; } } else { // Or list Item_cond_or *new_cond=new Item_cond_or; if (!new_cond) - return (COND*) 0; // OOM /* purecov: inspected */ + return ret; // OOM /* purecov: inspected */ List_iterator li(*((Item_cond*) cond)->argument_list()); Item *item; while ((item=li++)) { Item *fix=make_cond_for_table(item,tables,0L); if (!fix) - return (COND*) 0; // Always true + return ret; // Always true new_cond->argument_list()->push_back(fix); } /* @@ -11647,40 +11629,55 @@ new_cond->quick_fix_field(); new_cond->used_tables_cache= ((Item_cond_or*) cond)->used_tables_cache; new_cond->top_level_item(); - return new_cond; + ret= new_cond; } - } - - /* - Because the following test takes a while and it can be done - table_count times, we mark each item that we have examined with the result - of the test - */ - - if (cond->marker == 3 || (cond->used_tables() & ~tables)) - return (COND*) 0; // Can't check this yet - if (cond->marker == 2 || cond->eq_cmp_result() == Item::COND_OK) - return cond; // Not boolean op + break; + case Item::FUNC_ITEM: + /* + Because the following test takes a while and it can be done + table_count times, we mark each item that we have examined + with the result of the test + */ - if (((Item_func*) cond)->functype() == Item_func::EQ_FUNC) - { - Item *left_item= ((Item_func*) cond)->arguments()[0]; - Item *right_item= ((Item_func*) cond)->arguments()[1]; - if (left_item->type() == Item::FIELD_ITEM && - test_if_ref((Item_field*) left_item,right_item)) + if (cond->marker == 3 || (used_tables & ~tables)) + break; // Can't check this yet + if (cond->marker == 2 || cond->eq_cmp_result() == Item::COND_OK) { - cond->marker=3; // Checked when read - return (COND*) 0; + ret= cond; // Not boolean op + break; } - if (right_item->type() == Item::FIELD_ITEM && - test_if_ref((Item_field*) right_item,left_item)) + if (((Item_func*) cond)->functype() == Item_func::EQ_FUNC) { - cond->marker=3; // Checked when read - return (COND*) 0; + Item *left_item= ((Item_func*) cond)->arguments()[0]; + Item *right_item= ((Item_func*) cond)->arguments()[1]; + if (left_item->type() == Item::FIELD_ITEM && + test_if_ref((Item_field*) left_item,right_item)) + { + cond->marker= 3; // Checked when read + break; + } + if (right_item->type() == Item::FIELD_ITEM && + test_if_ref((Item_field*) right_item,left_item)) + { + cond->marker= 3; // Checked when read + break; + } } + cond->marker= 2; + ret= cond; + break; + case Item::SUBSELECT_ITEM: + if (used_table || !(used_tables & ~tables)) + ret= cond; + break; + default: + /* + Nothing special so far, just check used tables map + */ + if ((used_tables && !(used_tables & ~tables)) || cond->real_item()->const_item()) + ret= cond; } - cond->marker=2; - return cond; + return ret; } static Item *