diff options
author | unknown <tsmith@quadxeon.mysql.com> | 2007-05-21 20:50:08 +0200 |
---|---|---|
committer | unknown <tsmith@quadxeon.mysql.com> | 2007-05-21 20:50:08 +0200 |
commit | 221e23ad721cb98156ff313d6ee924c88765782e (patch) | |
tree | 250875cd3699ebe9837bdd77ab3f2b35ff4eb6e0 /sql | |
parent | f40047df9c72d1516d9a2f7d121dc7ce165ef419 (diff) | |
parent | 8b33c41554b1f9ac173a047f55fa0c522f28af35 (diff) | |
download | mariadb-git-221e23ad721cb98156ff313d6ee924c88765782e.tar.gz |
Merge quadxeon.mysql.com:/benchmarks/ext3/TOSAVE/tsmith/bk/50
into quadxeon.mysql.com:/benchmarks/ext3/TOSAVE/tsmith/bk/maint/50
configure.in:
Auto merged
mysql-test/r/strict.result:
Auto merged
mysql-test/r/type_datetime.result:
Auto merged
mysql-test/t/type_datetime.test:
Auto merged
sql/item.cc:
Auto merged
sql/item_cmpfunc.cc:
Auto merged
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 3 | ||||
-rw-r--r-- | sql/item_cmpfunc.cc | 20 | ||||
-rw-r--r-- | sql/item_sum.cc | 9 | ||||
-rw-r--r-- | sql/opt_sum.cc | 86 | ||||
-rw-r--r-- | sql/sql_select.cc | 6 | ||||
-rw-r--r-- | sql/sql_union.cc | 10 |
6 files changed, 112 insertions, 22 deletions
diff --git a/sql/item.cc b/sql/item.cc index 4f7d1cb56c0..92ea35072f9 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -3522,7 +3522,8 @@ Item_field::fix_outer_field(THD *thd, Field **from_field, Item **reference) prev_subselect_item->const_item_cache= 0; set_field(*from_field); if (!last_checked_context->select_lex->having_fix_field && - select->group_list.elements) + select->group_list.elements && + (place == SELECT_LIST || place == IN_HAVING)) { Item_outer_ref *rf; /* diff --git a/sql/item_cmpfunc.cc b/sql/item_cmpfunc.cc index 92a6f5c06da..0de9ef3e9ad 100644 --- a/sql/item_cmpfunc.cc +++ b/sql/item_cmpfunc.cc @@ -637,7 +637,13 @@ Arg_comparator::can_compare_as_dates(Item *a, Item *b, ulonglong *const_value) if (cmp_type != CMP_DATE_DFLT) { - if (cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item()) + /* + Do not cache GET_USER_VAR() function as its const_item() may return TRUE + for the current thread but it still may change during the execution. + */ + if (cmp_type != CMP_DATE_WITH_DATE && str_arg->const_item() && + (str_arg->type() != Item::FUNC_ITEM || + ((Item_func*)str_arg)->functype() != Item_func::GUSERVAR_FUNC)) { THD *thd= current_thd; ulonglong value; @@ -665,7 +671,7 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, Item_result type) { enum enum_date_cmp_type cmp_type; - ulonglong const_value; + ulonglong const_value= (ulonglong)-1; a= a1; b= a2; @@ -678,8 +684,7 @@ int Arg_comparator::set_cmp_func(Item_bool_func2 *owner_arg, a_cache= 0; b_cache= 0; - if (cmp_type != CMP_DATE_WITH_DATE && - ((*b)->const_item() || (*a)->const_item())) + if (const_value != (ulonglong)-1) { Item_cache_int *cache= new Item_cache_int(); /* Mark the cache as non-const to prevent re-caching. */ @@ -785,7 +790,12 @@ get_datetime_value(THD *thd, Item ***item_arg, Item **cache_arg, MYSQL_TYPE_DATE ? MYSQL_TIMESTAMP_DATE : MYSQL_TIMESTAMP_DATETIME; value= get_date_from_str(thd, str, t_type, warn_item->name, &error); } - if (item->const_item() && cache_arg) + /* + Do not cache GET_USER_VAR() function as its const_item() may return TRUE + for the current thread but it still may change during the execution. + */ + if (item->const_item() && cache_arg && (item->type() != Item::FUNC_ITEM || + ((Item_func*)item)->functype() != Item_func::GUSERVAR_FUNC)) { Item_cache_int *cache= new Item_cache_int(); /* Mark the cache as non-const to prevent re-caching. */ diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 4579ecd48ae..d6b31d43389 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -3339,6 +3339,10 @@ String* Item_func_group_concat::val_str(String* str) DBUG_ASSERT(fixed == 1); if (null_value) return 0; + if (!result.length() && tree) + /* Tree is used for sorting as in ORDER BY */ + tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this, + left_root_right); if (count_cut_values && !warning) { /* @@ -3350,11 +3354,6 @@ String* Item_func_group_concat::val_str(String* str) ER_CUT_VALUE_GROUP_CONCAT, ER(ER_CUT_VALUE_GROUP_CONCAT)); } - if (result.length()) - return &result; - if (tree) - tree_walk(tree, (tree_walk_action)&dump_leaf_key, (void*)this, - left_root_right); return &result; } diff --git a/sql/opt_sum.cc b/sql/opt_sum.cc index 9222e15ff91..b9de54dbf5c 100644 --- a/sql/opt_sum.cc +++ b/sql/opt_sum.cc @@ -206,12 +206,68 @@ int opt_sum_query(TABLE_LIST *tables, List<Item> &all_fields,COND *conds) if (!ref.key_length) error= table->file->index_first(table->record[0]); - else - error= table->file->index_read(table->record[0],key_buff, - ref.key_length, - range_fl & NEAR_MIN ? - HA_READ_AFTER_KEY : - HA_READ_KEY_OR_NEXT); + else + { + /* + Use index to replace MIN/MAX functions with their values + according to the following rules: + + 1) Insert the minimum non-null values where the WHERE clause still + matches, or + 2) a NULL value if there are only NULL values for key_part_k. + 3) Fail, producing a row of nulls + + Implementation: Read the smallest value using the search key. If + the interval is open, read the next value after the search + key. If read fails, and we're looking for a MIN() value for a + nullable column, test if there is an exact match for the key. + */ + if (!(range_fl & NEAR_MIN)) + /* + Closed interval: Either The MIN argument is non-nullable, or + we have a >= predicate for the MIN argument. + */ + error= table->file->index_read(table->record[0], ref.key_buff, + ref.key_length, + HA_READ_KEY_OR_NEXT); + else + { + /* + Open interval: There are two cases: + 1) We have only MIN() and the argument column is nullable, or + 2) there is a > predicate on it, nullability is irrelevant. + We need to scan the next bigger record first. + */ + error= table->file->index_read(table->record[0], ref.key_buff, + ref.key_length, HA_READ_AFTER_KEY); + /* + If the found record is outside the group formed by the search + prefix, or there is no such record at all, check if all + records in that group have NULL in the MIN argument + column. If that is the case return that NULL. + + Check if case 1 from above holds. If it does, we should read + the skipped tuple. + */ + if (ref.key_buff[prefix_len] == 1 && + /* + Last keypart (i.e. the argument to MIN) is set to NULL by + find_key_for_maxmin only if all other keyparts are bound + to constants in a conjunction of equalities. Hence, we + can detect this by checking only if the last keypart is + NULL. + */ + (error == HA_ERR_KEY_NOT_FOUND || + key_cmp_if_same(table, ref.key_buff, ref.key, prefix_len))) + { + DBUG_ASSERT(item_field->field->real_maybe_null()); + error= table->file->index_read(table->record[0], ref.key_buff, + ref.key_length, + HA_READ_KEY_EXACT); + } + } + } + /* Verify that the read tuple indeed matches the search key */ if (!error && reckey_in_range(0, &ref, item_field->field, conds, range_fl, prefix_len)) error= HA_ERR_KEY_NOT_FOUND; @@ -739,14 +795,24 @@ static bool find_key_for_maxmin(bool max_fl, TABLE_REF *ref, if (!max_fl && key_part_used == key_part_to_use && part->null_bit) { /* - SELECT MIN(key_part2) FROM t1 WHERE key_part1=const - If key_part2 may be NULL, then we want to find the first row - that is not null + The query is on this form: + + SELECT MIN(key_part_k) + FROM t1 + WHERE key_part_1 = const and ... and key_part_k-1 = const + + If key_part_k is nullable, we want to find the first matching row + where key_part_k is not null. The key buffer is now {const, ..., + NULL}. This will be passed to the handler along with a flag + indicating open interval. If a tuple is read that does not match + these search criteria, an attempt will be made to read an exact + match for the key buffer. */ + /* Set the first byte of key_part_k to 1, that means NULL */ ref->key_buff[ref->key_length]= 1; ref->key_length+= part->store_length; *range_fl&= ~NO_MIN_RANGE; - *range_fl|= NEAR_MIN; // > NULL + *range_fl|= NEAR_MIN; // Open interval } /* The following test is false when the key in the key tree is diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 967322600a7..ea59cbbe9f2 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -976,6 +976,12 @@ JOIN::optimize() } } + if (conds &&!outer_join && const_table_map != found_const_table_map && + (select_options & SELECT_DESCRIBE) && + select_lex->master_unit() == &thd->lex->unit) // upper level SELECT + { + conds=new Item_int((longlong) 0,1); // Always false + } if (make_join_select(this, select, conds)) { zero_result_cause= diff --git a/sql/sql_union.cc b/sql/sql_union.cc index 7fb75732012..373b03d45e6 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -147,8 +147,16 @@ st_select_lex_unit::init_prepare_fake_select_lex(THD *thd_arg) fake_select_lex->table_list.link_in_list((byte *)&result_table_list, (byte **) &result_table_list.next_local); - fake_select_lex->context.table_list= fake_select_lex->context.first_name_resolution_table= + fake_select_lex->context.table_list= + fake_select_lex->context.first_name_resolution_table= fake_select_lex->get_table_list(); + if (!fake_select_lex->first_execution) + { + for (ORDER *order= (ORDER *) global_parameters->order_list.first; + order; + order= order->next) + order->item= &order->item_ptr; + } for (ORDER *order= (ORDER *)global_parameters->order_list.first; order; order=order->next) |