diff options
author | unknown <gshchepa/uchum@gleb.loc> | 2007-08-11 02:00:51 +0500 |
---|---|---|
committer | unknown <gshchepa/uchum@gleb.loc> | 2007-08-11 02:00:51 +0500 |
commit | 6aa5fa3a1dbbee863fb4a0da153cedff6b69a418 (patch) | |
tree | 2380b8a509f41895330745de2a1f4255304c4929 /sql | |
parent | 6930ac54068b88ce5ca2476f70d74ddb42f5d9fc (diff) | |
parent | 124ad307e3306fc1de749234b7a4e7708f620d57 (diff) | |
download | mariadb-git-6aa5fa3a1dbbee863fb4a0da153cedff6b69a418.tar.gz |
Merge gleb.loc:/home/uchum/work/bk/5.1
into gleb.loc:/home/uchum/work/bk/5.1-opt
sql/field.cc:
Auto merged
BitKeeper/deleted/.del-readme.txt~3:
Auto merged
sql/field.h:
Auto merged
sql/handler.cc:
Auto merged
sql/mysqld.cc:
Auto merged
sql/sql_class.cc:
Auto merged
sql/sql_class.h:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_table.cc:
Auto merged
sql/unireg.h:
Auto merged
sql/sql_select.cc:
Merge with main tree.
Diffstat (limited to 'sql')
-rw-r--r-- | sql/field.cc | 6 | ||||
-rw-r--r-- | sql/field.h | 13 | ||||
-rw-r--r-- | sql/mysqld.cc | 6 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 2 | ||||
-rw-r--r-- | sql/sql_class.h | 3 | ||||
-rw-r--r-- | sql/sql_parse.cc | 5 | ||||
-rw-r--r-- | sql/sql_select.cc | 314 | ||||
-rw-r--r-- | sql/sql_select.h | 6 | ||||
-rw-r--r-- | sql/time.cc | 2 | ||||
-rw-r--r-- | sql/unireg.h | 2 |
10 files changed, 276 insertions, 83 deletions
diff --git a/sql/field.cc b/sql/field.cc index acaf1576a8f..4af5dd5ebd6 100644 --- a/sql/field.cc +++ b/sql/field.cc @@ -4655,6 +4655,7 @@ longlong Field_timestamp::val_int(void) MYSQL_TIME time_tmp; THD *thd= table ? table->in_use : current_thd; + thd->time_zone_used= 1; #ifdef WORDS_BIGENDIAN if (table && table->s->db_low_byte_first) temp=uint4korr(ptr); @@ -4666,7 +4667,6 @@ longlong Field_timestamp::val_int(void) return(0); /* purecov: inspected */ thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t)temp); - thd->time_zone_used= 1; return time_tmp.year * LL(10000000000) + time_tmp.month * LL(100000000) + time_tmp.day * 1000000L + time_tmp.hour * 10000L + @@ -4686,6 +4686,7 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr) to= (char*) val_buffer->ptr(); val_buffer->length(field_length); + thd->time_zone_used= 1; #ifdef WORDS_BIGENDIAN if (table && table->s->db_low_byte_first) temp=uint4korr(ptr); @@ -4701,7 +4702,6 @@ String *Field_timestamp::val_str(String *val_buffer, String *val_ptr) val_buffer->set_charset(&my_charset_bin); // Safety thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,(my_time_t)temp); - thd->time_zone_used= 1; temp= time_tmp.year % 100; if (temp < YY_PART_YEAR - 1) @@ -4751,6 +4751,7 @@ bool Field_timestamp::get_date(MYSQL_TIME *ltime, uint fuzzydate) { long temp; THD *thd= table ? table->in_use : current_thd; + thd->time_zone_used= 1; #ifdef WORDS_BIGENDIAN if (table && table->s->db_low_byte_first) temp=uint4korr(ptr); @@ -4766,7 +4767,6 @@ bool Field_timestamp::get_date(MYSQL_TIME *ltime, uint fuzzydate) else { thd->variables.time_zone->gmt_sec_to_TIME(ltime, (my_time_t)temp); - thd->time_zone_used= 1; } return 0; } diff --git a/sql/field.h b/sql/field.h index 60f6fc19d76..fa17f44a55b 100644 --- a/sql/field.h +++ b/sql/field.h @@ -275,9 +275,9 @@ public: if (null_ptr) null_ptr=ADD_TO_PTR(null_ptr,ptr_diff,uchar*); } - inline void get_image(uchar *buff,uint length, CHARSET_INFO *cs) + virtual void get_image(uchar *buff, uint length, CHARSET_INFO *cs) { memcpy(buff,ptr,length); } - inline void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) + virtual void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) { memcpy(ptr,buff,length); } @@ -1586,7 +1586,10 @@ public: virtual bool str_needs_quotes() { return TRUE; } my_decimal *val_decimal(my_decimal *); int cmp(const uchar *a, const uchar *b) - { return cmp_binary(a, b); } + { + DBUG_ASSERT(ptr == a); + return Field_bit::key_cmp(b, bytes_in_rec+test(bit_len)); + } int cmp_binary_offset(uint row_offset) { return cmp_offset(row_offset); } int cmp_max(const uchar *a, const uchar *b, uint max_length); @@ -1594,6 +1597,10 @@ public: { return cmp_binary((uchar *) a, (uchar *) b); } int key_cmp(const uchar *str, uint length); int cmp_offset(uint row_offset); + void get_image(uchar *buff, uint length, CHARSET_INFO *cs) + { get_key_image(buff, length, itRAW); } + void set_image(const uchar *buff,uint length, CHARSET_INFO *cs) + { Field_bit::store((char *) buff, length, cs); } uint get_key_image(uchar *buff, uint length, imagetype type); void set_key_image(const uchar *buff, uint length) { Field_bit::store((char*) buff, length, &my_charset_bin); } diff --git a/sql/mysqld.cc b/sql/mysqld.cc index fe4f83dd79e..6c8fa7e7ac3 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -5073,6 +5073,7 @@ enum options_mysqld OPT_PLUGIN_DIR, OPT_LOG_OUTPUT, OPT_PORT_OPEN_TIMEOUT, + OPT_KEEP_FILES_ON_CREATE, OPT_GENERAL_LOG, OPT_SLOW_LOG, OPT_THREAD_HANDLING, @@ -5950,6 +5951,11 @@ log and this option does nothing anymore.", (uchar**) &max_system_variables.join_buff_size, 0, GET_ULONG, REQUIRED_ARG, 128*1024L, IO_SIZE*2+MALLOC_OVERHEAD, ~0L, MALLOC_OVERHEAD, IO_SIZE, 0}, + {"keep_files_on_create", OPT_KEEP_FILES_ON_CREATE, + "Don't overwrite stale .MYD and .MYI even if no directory is specified.", + (uchar**) &global_system_variables.keep_files_on_create, + (uchar**) &max_system_variables.keep_files_on_create, + 0, GET_BOOL, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"key_buffer_size", OPT_KEY_BUFFER_SIZE, "The size of the buffer used for index blocks for MyISAM tables. Increase this to get better index handling (for all reads and multiple writes) to as much as you can afford; 64M on a 256M machine that mainly runs MySQL is quite common.", (uchar**) &dflt_key_cache_var.param_buff_size, diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index 966e841ccbf..8ecba1d4be0 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5654,6 +5654,8 @@ ER_NON_INSERTABLE_TABLE ger "Die Zieltabelle %-.100s von %s ist nicht einfügbar" ER_ADMIN_WRONG_MRG_TABLE eng "Table '%-.64s' is differently defined or of non-MyISAM type or doesn't exist" +ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT + eng "Too high level of nesting for select" ER_FOREIGN_SERVER_EXISTS eng "The foreign server, %s, you are trying to create already exists." ER_FOREIGN_SERVER_DOESNT_EXIST diff --git a/sql/sql_class.h b/sql/sql_class.h index ef4869fa244..df79d82732f 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -424,6 +424,8 @@ typedef struct system_status_var #define last_system_status_var com_stmt_close +void mark_transaction_to_rollback(THD *thd, bool all); + #ifdef MYSQL_SERVER void free_tmp_table(THD *thd, TABLE *entry); @@ -2482,6 +2484,7 @@ public: /* Functions in sql_class.cc */ void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var); + void add_diff_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var, STATUS_VAR *dec_var); void mark_transaction_to_rollback(THD *thd, bool all); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index d38c9bd8643..0d7158a4eee 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -5251,6 +5251,11 @@ mysql_new_select(LEX *lex, bool move_down) select_lex->init_query(); select_lex->init_select(); lex->nest_level++; + if (lex->nest_level > (int) MAX_SELECT_NESTING) + { + my_error(ER_TOO_HIGH_LEVEL_OF_NESTING_FOR_SELECT,MYF(0),MAX_SELECT_NESTING); + DBUG_RETURN(1); + } select_lex->nest_level= lex->nest_level; /* Don't evaluate this subquery during statement prepare even if diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 0da3b4af547..6f3851b66a1 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -6448,6 +6448,7 @@ void JOIN_TAB::cleanup() quick= 0; x_free(cache.buff); cache.buff= 0; + limit= 0; if (table) { if (table->key_read) @@ -12586,9 +12587,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, { int ref_key; uint ref_key_parts; + int order_direction; + uint used_key_parts; TABLE *table=tab->table; SQL_SELECT *select=tab->select; key_map usable_keys; + QUICK_SELECT_I *save_quick= 0; DBUG_ENTER("test_if_skip_sort_order"); LINT_INIT(ref_key_parts); @@ -12623,6 +12627,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, else if (select && select->quick) // Range found by opt_range { int quick_type= select->quick->get_type(); + save_quick= select->quick; /* assume results are not ordered when index merge is used TODO: sergeyp: Results of all index merge selects actually are ordered @@ -12642,8 +12647,6 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, /* We come here when there is a REF key. */ - int order_direction; - uint used_key_parts; if (!usable_keys.is_set(ref_key)) { /* @@ -12704,63 +12707,33 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, } /* Check if we get the rows in requested sorted order by using the key */ if (usable_keys.is_set(ref_key) && - (order_direction = test_if_order_by_key(order,table,ref_key, - &used_key_parts))) - { - if (order_direction == -1) // If ORDER BY ... DESC - { - if (select && select->quick) - { - /* - Don't reverse the sort order, if it's already done. - (In some cases test_if_order_by_key() can be called multiple times - */ - if (!select->quick->reverse_sorted()) - { - QUICK_SELECT_DESC *tmp; - int quick_type= select->quick->get_type(); - if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE || - quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT || - quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION || - quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) - DBUG_RETURN(0); // Use filesort - - /* ORDER BY range_key DESC */ - tmp= new QUICK_SELECT_DESC((QUICK_RANGE_SELECT*)(select->quick), - used_key_parts); - if (!tmp || tmp->error) - { - delete tmp; - DBUG_RETURN(0); // Reverse sort not supported - } - select->quick=tmp; - } - DBUG_RETURN(1); - } - if (tab->ref.key_parts < used_key_parts) - { - /* - SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC - - Use a traversal function that starts by reading the last row - with key part (A) and then traverse the index backwards. - */ - tab->read_first_record= join_read_last_key; - tab->read_record.read_record= join_read_prev_same; - /* fall through */ - } - } - else if (select && select->quick) - select->quick->sorted= 1; - DBUG_RETURN(1); /* No need to sort */ - } + (order_direction= test_if_order_by_key(order,table,ref_key, + &used_key_parts))) + goto check_reverse_order; } - else { - /* check if we can use a key to resolve the group */ - /* Tables using JT_NEXT are handled here */ + /* + Check whether there is an index compatible with the given order + usage of which is cheaper than usage of the ref_key index (ref_key>=0) + or a table scan. + It may be the case if ORDER/GROUP BY is used with LIMIT. + */ uint nr; key_map keys; + uint best_key_parts; + int best_key_direction; + ha_rows best_records; + double read_time; + int best_key= -1; + bool is_best_covering= FALSE; + double fanout= 1; + JOIN *join= tab->join; + uint tablenr= tab - join->join_tab; + ha_rows table_records= table->file->stats.records; + bool group= join->group && order == join->group_list; + LINT_INIT(best_key_parts); + LINT_INIT(best_key_direction); + LINT_INIT(best_records); /* filesort() and join cache are usually faster than reading in @@ -12773,7 +12746,7 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, resolved with a key; This is because filesort() is usually faster than retrieving all rows through an index. */ - if (select_limit >= table->file->stats.records) + if (select_limit >= table_records) { keys= *table->file->keys_to_use_for_scanning(); keys.merge(table->covering_keys); @@ -12784,38 +12757,227 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, This is to allow users to use index in ORDER BY. */ if (table->force_index) - keys.merge(table->keys_in_use_for_query); + keys.merge(group ? table->keys_in_use_for_group_by : + table->keys_in_use_for_order_by); keys.intersect(usable_keys); } else keys= usable_keys; + read_time= join->best_positions[tablenr].read_time; + for (uint i= tablenr+1; i < join->tables; i++) + fanout*= join->best_positions[i].records_read; // fanout is always >= 1 + for (nr=0; nr < table->s->keys ; nr++) { - uint not_used; - if (keys.is_set(nr)) + int direction; + if (keys.is_set(nr) && + (direction= test_if_order_by_key(order, table, nr, &used_key_parts))) { - int flag; - if ((flag= test_if_order_by_key(order, table, nr, ¬_used))) + bool is_covering= table->covering_keys.is_set(nr) || + nr == table->s->primary_key && + table->file->primary_key_is_clustered(); + + /* + Don't use an index scan with ORDER BY without limit. + For GROUP BY without limit always use index scan + if there is a suitable index. + Why we hold to this asymmetry hardly can be explained + rationally. It's easy to demonstrate that using + temporary table + filesort could be cheaper for grouping + queries too. + */ + if (is_covering || + select_limit != HA_POS_ERROR || + ref_key < 0 && (group || table->force_index)) + { + double rec_per_key; + double index_scan_time; + KEY *keyinfo= tab->table->key_info+nr; + if (select_limit == HA_POS_ERROR) + select_limit= table_records; + if (group) + { + rec_per_key= keyinfo->rec_per_key[used_key_parts-1]; + set_if_bigger(rec_per_key, 1); + /* + With a grouping query each group containing on average + rec_per_key records produces only one row that will + be included into the result set. + */ + if (select_limit > table_records/rec_per_key) + select_limit= table_records; + else + select_limit= (ha_rows) (select_limit*rec_per_key); + } + /* + If tab=tk is not the last joined table tn then to get first + L records from the result set we can expect to retrieve + only L/fanout(tk,tn) where fanout(tk,tn) says how many + rows in the record set on average will match each row tk. + Usually our estimates for fanouts are too pessimistic. + So the estimate for L/fanout(tk,tn) will be too optimistic + and as result we'll choose an index scan when using ref/range + access + filesort will be cheaper. + */ + select_limit= (ha_rows) (select_limit < fanout ? + 1 : select_limit/fanout); + /* + We assume that each of the tested indexes is not correlated + with ref_key. Thus, to select first N records we have to scan + N/selectivity(ref_key) index entries. + selectivity(ref_key) = #scanned_records/#table_records = + table->quick_condition_rows/table_records. + In any case we can't select more than #table_records. + N/(table->quick_condition_rows/table_records) > table_records + <=> N > table->quick_condition_rows. + */ + if (select_limit > table->quick_condition_rows) + select_limit= table_records; + else + select_limit= (ha_rows) (select_limit * + (double) table_records / + table->quick_condition_rows); + rec_per_key= keyinfo->rec_per_key[keyinfo->key_parts-1]; + set_if_bigger(rec_per_key, 1); + /* + Here we take into account the fact that rows are + accessed in sequences rec_per_key records in each. + Rows in such a sequence are supposed to be ordered + by rowid/primary key. When reading the data + in a sequence we'll touch not more pages than the + table file contains. + TODO. Use the formula for a disk sweep sequential access + to calculate the cost of accessing data rows for one + index entry. + */ + index_scan_time= select_limit/rec_per_key * + min(rec_per_key, table->file->scan_time()); + if (is_covering || + ref_key < 0 && (group || table->force_index) || + index_scan_time < read_time) + { + ha_rows quick_records= table_records; + if (is_best_covering && !is_covering) + continue; + if (table->quick_keys.is_set(nr)) + quick_records= table->quick_rows[nr]; + if (best_key < 0 || + (select_limit <= min(quick_records,best_records) ? + keyinfo->key_parts < best_key_parts : + quick_records < best_records)) + { + best_key= nr; + best_key_parts= keyinfo->key_parts; + best_records= quick_records; + is_best_covering= is_covering; + best_key_direction= direction; + } + } + } + } + } + if (best_key >= 0) + { + bool quick_created= FALSE; + if (table->quick_keys.is_set(best_key) && best_key != ref_key) + { + key_map map; + map.clear_all(); // Force the creation of quick select + map.set_bit(best_key); // only best_key. + quick_created= + select->test_quick_select(join->thd, map, 0, + join->select_options & OPTION_FOUND_ROWS ? + HA_POS_ERROR : + join->unit->select_limit_cnt, + 0) > 0; + } + if (!no_changes) + { + if (!quick_created) { - if (!no_changes) - { - tab->index=nr; - tab->read_first_record= (flag > 0 ? join_read_first: - join_read_last); - tab->type=JT_NEXT; // Read with index_first(), index_next() - if (table->covering_keys.is_set(nr)) - { - table->key_read=1; - table->file->extra(HA_EXTRA_KEYREAD); - } - } - DBUG_RETURN(1); + tab->index= best_key; + tab->read_first_record= best_key_direction > 0 ? + join_read_first:join_read_last; + tab->type=JT_NEXT; // Read with index_first(), index_next() + if (table->covering_keys.is_set(best_key)) + { + table->key_read=1; + table->file->extra(HA_EXTRA_KEYREAD); + } + table->file->ha_index_or_rnd_end(); + if (join->select_options & SELECT_DESCRIBE) + { + tab->ref.key= -1; + tab->ref.key_parts= 0; + if (select && select->quick) + { + delete select->quick; + select->quick= 0; + } + if (select_limit < table_records) + tab->limit= select_limit; + } + } + } + used_key_parts= best_key_parts; + order_direction= best_key_direction; + } + else + DBUG_RETURN(0); + } + +check_reverse_order: + if (order_direction == -1) // If ORDER BY ... DESC + { + if (select && select->quick) + { + /* + Don't reverse the sort order, if it's already done. + (In some cases test_if_order_by_key() can be called multiple times + */ + if (!select->quick->reverse_sorted()) + { + QUICK_SELECT_DESC *tmp; + int quick_type= select->quick->get_type(); + if (quick_type == QUICK_SELECT_I::QS_TYPE_INDEX_MERGE || + quick_type == QUICK_SELECT_I::QS_TYPE_ROR_INTERSECT || + quick_type == QUICK_SELECT_I::QS_TYPE_ROR_UNION || + quick_type == QUICK_SELECT_I::QS_TYPE_GROUP_MIN_MAX) + { + tab->limit= 0; + select->quick= save_quick; + DBUG_RETURN(0); // Use filesort + } + + /* ORDER BY range_key DESC */ + tmp= new QUICK_SELECT_DESC((QUICK_RANGE_SELECT*)(select->quick), + used_key_parts); + if (!tmp || tmp->error) + { + delete tmp; + select->quick= save_quick; + tab->limit= 0; + DBUG_RETURN(0); // Reverse sort not supported } + select->quick=tmp; } } + else if (tab->ref.key >= 0 && tab->ref.key_parts < used_key_parts) + { + /* + SELECT * FROM t1 WHERE a=1 ORDER BY a DESC,b DESC + + Use a traversal function that starts by reading the last row + with key part (A) and then traverse the index backwards. + */ + tab->read_first_record= join_read_last_key; + tab->read_record.read_record= join_read_prev_same; + } } - DBUG_RETURN(0); // Can't use index. + else if (select && select->quick) + select->quick->sorted= 1; + DBUG_RETURN(1); } @@ -15554,7 +15716,7 @@ static void select_describe(JOIN *join, bool need_tmp_table, bool need_order, if (tab->select && tab->select->quick) examined_rows= tab->select->quick->records; else if (tab->type == JT_NEXT || tab->type == JT_ALL) - examined_rows= tab->table->file->records(); + examined_rows= tab->limit ? tab->limit : tab->table->file->records(); else examined_rows=(ha_rows)join->best_positions[i].records_read; diff --git a/sql/sql_select.h b/sql/sql_select.h index d1acad1c5d6..efa92432e2b 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -194,6 +194,12 @@ typedef struct st_join_table { enum join_type type; bool cached_eq_ref_table,eq_ref_table,not_used_in_distinct; bool sorted; + /* + If it's not 0 the number stored this field indicates that the index + scan has been chosen to access the table data and we expect to scan + this number of rows for the table. + */ + ha_rows limit; TABLE_REF ref; JOIN_CACHE cache; JOIN *join; diff --git a/sql/time.cc b/sql/time.cc index c552d085f5e..a6619cf4cee 100644 --- a/sql/time.cc +++ b/sql/time.cc @@ -263,11 +263,11 @@ my_time_t TIME_to_timestamp(THD *thd, const MYSQL_TIME *t, my_bool *in_dst_time_ my_time_t timestamp; *in_dst_time_gap= 0; + thd->time_zone_used= 1; timestamp= thd->variables.time_zone->TIME_to_gmt_sec(t, in_dst_time_gap); if (timestamp) { - thd->time_zone_used= 1; return timestamp; } diff --git a/sql/unireg.h b/sql/unireg.h index 232ea5e70e7..b368eee6f0e 100644 --- a/sql/unireg.h +++ b/sql/unireg.h @@ -85,6 +85,8 @@ #define MAX_FIELDS 4096 /* Limit in the .frm file */ #define MAX_PARTITIONS 1024 +#define MAX_SELECT_NESTING (sizeof(nesting_map)*8-1) + #define MAX_SORT_MEMORY (2048*1024-MALLOC_OVERHEAD) #define MIN_SORT_MEMORY (32*1024-MALLOC_OVERHEAD) |