diff options
Diffstat (limited to 'sql')
-rw-r--r-- | sql/item.cc | 11 | ||||
-rw-r--r-- | sql/mysql_priv.h | 3 | ||||
-rw-r--r-- | sql/sql_base.cc | 7 | ||||
-rw-r--r-- | sql/sql_class.cc | 2 | ||||
-rw-r--r-- | sql/sql_handler.cc | 49 | ||||
-rw-r--r-- | sql/sql_lex.cc | 1 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_select.cc | 17 | ||||
-rw-r--r-- | sql/sql_table.cc | 6 |
9 files changed, 82 insertions, 16 deletions
diff --git a/sql/item.cc b/sql/item.cc index 8737cc06bbd..38b6516b742 100644 --- a/sql/item.cc +++ b/sql/item.cc @@ -348,7 +348,18 @@ bool Item_field::fix_fields(THD *thd,TABLE_LIST *tables) { Field *tmp; if (!(tmp=find_field_in_tables(thd,this,tables))) + { + if (thd->lex.select_lex.is_item_list_lookup) + { + Item **res= find_item_in_list(this, thd->lex.select_lex.item_list); + if (res && (*res)->type() == Item::FIELD_ITEM) + { + set_field((*((Item_field**)res))->field); + return 0; + } + } return 1; + } set_field(tmp); } else if (thd && thd->set_query_id && field->query_id != thd->query_id) diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 21d7afbd6cb..62e65ea95da 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -549,7 +549,8 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen= 0); int mysql_ha_close(THD *thd, TABLE_LIST *tables); int mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *, List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows); -int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags); +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, + bool is_locked); /* mysql_ha_flush mode_flags bits */ #define MYSQL_HA_CLOSE_FINAL 0x00 #define MYSQL_HA_REOPEN_ON_USAGE 0x01 diff --git a/sql/sql_base.cc b/sql/sql_base.cc index bc2ad9fff50..4f52904a61e 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -390,7 +390,8 @@ bool close_cached_tables(THD *thd, bool if_wait_for_refresh, thd->proc_info="Flushing tables"; close_old_data_files(thd,thd->open_tables,1,1); - mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL); + mysql_ha_flush(thd, tables, MYSQL_HA_REOPEN_ON_USAGE | MYSQL_HA_FLUSH_ALL, + TRUE); bool found=1; /* Wait until all threads has closed all the tables we had locked */ DBUG_PRINT("info", ("Waiting for others threads to close their open tables")); @@ -863,7 +864,7 @@ TABLE *open_table(THD *thd,const char *db,const char *table_name, } /* close handler tables which are marked for flush */ - mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); for (table=(TABLE*) hash_search(&open_cache,(byte*) key,key_length) ; table && table->in_use ; @@ -1262,7 +1263,7 @@ bool wait_for_tables(THD *thd) { thd->some_tables_deleted=0; close_old_data_files(thd,thd->open_tables,0,dropping_tables != 0); - mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE); + mysql_ha_flush(thd, (TABLE_LIST*) NULL, MYSQL_HA_REOPEN_ON_USAGE, TRUE); if (!table_is_used(thd->open_tables,1)) break; (void) pthread_cond_wait(&COND_refresh,&LOCK_open); diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 9dd75b32d5d..66d23ada163 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -217,7 +217,7 @@ void THD::cleanup(void) close_thread_tables(this); } mysql_ha_flush(this, (TABLE_LIST*) 0, - MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL); + MYSQL_HA_CLOSE_FINAL | MYSQL_HA_FLUSH_ALL, FALSE); hash_free(&handler_tables_hash); close_temporary_tables(this); hash_free(&user_vars); diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc index fcdb2aeb668..28e94d1a477 100644 --- a/sql/sql_handler.cc +++ b/sql/sql_handler.cc @@ -357,6 +357,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, ha_rows select_limit,ha_rows offset_limit) { TABLE_LIST *hash_tables; + TABLE **table_ptr; TABLE *table; int err; int keyno=-1; @@ -379,6 +380,27 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables, DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' tab %p", hash_tables->db, hash_tables->real_name, hash_tables->alias, table)); + /* Table might have been flushed. */ + if (table && (table->version != refresh_version)) + { + /* + We must follow the thd->handler_tables chain, as we need the + address of the 'next' pointer referencing this table + for close_thread_table(). + */ + for (table_ptr= &(thd->handler_tables); + *table_ptr && (*table_ptr != table); + table_ptr= &(*table_ptr)->next) + {} + VOID(pthread_mutex_lock(&LOCK_open)); + if (close_thread_table(thd, table_ptr)) + { + /* Tell threads waiting for refresh that something has happened */ + VOID(pthread_cond_broadcast(&COND_refresh)); + } + VOID(pthread_mutex_unlock(&LOCK_open)); + table= hash_tables->table= NULL; + } if (!table) { /* @@ -593,6 +615,7 @@ err0: MYSQL_HA_REOPEN_ON_USAGE mark for reopen. MYSQL_HA_FLUSH_ALL flush all tables, not only those marked for flush. + is_locked If LOCK_open is locked. DESCRIPTION The list of HANDLER tables may be NULL, in which case all HANDLER @@ -600,7 +623,6 @@ err0: If 'tables' is NULL and MYSQL_HA_FLUSH_ALL is not set, all HANDLER tables marked for flush are closed. Broadcasts a COND_refresh condition, for every table closed. - The caller must lock LOCK_open. NOTE Since mysql_ha_flush() is called when the base table has to be closed, @@ -610,10 +632,12 @@ err0: 0 ok */ -int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) +int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags, + bool is_locked) { TABLE_LIST *tmp_tables; TABLE **table_ptr; + bool did_lock= FALSE; DBUG_ENTER("mysql_ha_flush"); DBUG_PRINT("enter", ("tables: %p mode_flags: 0x%02x", tables, mode_flags)); @@ -637,6 +661,12 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) (*table_ptr)->table_cache_key, (*table_ptr)->real_name, (*table_ptr)->table_name)); + /* The first time it is required, lock for close_thread_table(). */ + if (! did_lock && ! is_locked) + { + VOID(pthread_mutex_lock(&LOCK_open)); + did_lock= TRUE; + } mysql_ha_flush_table(thd, table_ptr, mode_flags); continue; } @@ -655,6 +685,12 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) if ((mode_flags & MYSQL_HA_FLUSH_ALL) || ((*table_ptr)->version != refresh_version)) { + /* The first time it is required, lock for close_thread_table(). */ + if (! did_lock && ! is_locked) + { + VOID(pthread_mutex_lock(&LOCK_open)); + did_lock= TRUE; + } mysql_ha_flush_table(thd, table_ptr, mode_flags); continue; } @@ -662,6 +698,10 @@ int mysql_ha_flush(THD *thd, TABLE_LIST *tables, uint mode_flags) } } + /* Release the lock if it was taken by this function. */ + if (did_lock) + VOID(pthread_mutex_unlock(&LOCK_open)); + DBUG_RETURN(0); } @@ -693,8 +733,8 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) table->table_name, mode_flags)); if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash, - (byte*) (*table_ptr)->table_name, - strlen((*table_ptr)->table_name) + 1))) + (byte*) table->table_name, + strlen(table->table_name) + 1))) { if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE)) { @@ -708,6 +748,7 @@ static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, uint mode_flags) } } + safe_mutex_assert_owner(&LOCK_open); if (close_thread_table(thd, table_ptr)) { /* Tell threads waiting for refresh that something has happened */ diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc index 20aacf42be0..9fb35e3f914 100644 --- a/sql/sql_lex.cc +++ b/sql/sql_lex.cc @@ -154,6 +154,7 @@ LEX *lex_start(THD *thd, uchar *buf,uint length) lex->slave_thd_opt=0; lex->sql_command=SQLCOM_END; bzero((char *)&lex->mi,sizeof(lex->mi)); + lex->select_lex.is_item_list_lookup= 0; return lex; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index ab78555262f..d4b20c69bf2 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -121,7 +121,7 @@ typedef struct st_select_lex ignore_index, *ignore_index_ptr; List<Item_func_match> ftfunc_list; uint in_sum_expr, sort_default; - bool create_refs, braces; + bool create_refs, braces, is_item_list_lookup; st_select_lex *next; } SELECT_LEX; diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 29c15741347..6dd68a60f88 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -626,6 +626,7 @@ mysql_select(THD *thd,TABLE_LIST *tables,List<Item> &fields,COND *conds, { order=0; // The output has only one row simple_order=1; + select_distinct= 0; // No need in distinct for 1 row } calc_group_buffer(&join,group); @@ -3115,7 +3116,7 @@ eq_ref_table(JOIN *join, ORDER *start_order, JOIN_TAB *tab) tab->cached_eq_ref_table=1; if (tab->type == JT_CONST) // We can skip const tables return (tab->eq_ref_table=1); /* purecov: inspected */ - if (tab->type != JT_EQ_REF) + if (tab->type != JT_EQ_REF || tab->table->maybe_null) return (tab->eq_ref_table=0); // We must use this Item **ref_item=tab->ref.items; Item **end=ref_item+tab->ref.key_parts; @@ -6002,8 +6003,12 @@ test_if_skip_sort_order(JOIN_TAB *tab,ORDER *order,ha_rows select_limit, key_map usable_keys; DBUG_ENTER("test_if_skip_sort_order"); - /* Check which keys can be used to resolve ORDER BY */ - usable_keys= ~(key_map) 0; + /* + Check which keys can be used to resolve ORDER BY. + We must not try to use disabled keys. + */ + usable_keys= table->keys_in_use; + for (ORDER *tmp_order=order; tmp_order ; tmp_order=tmp_order->next) { if ((*tmp_order->item)->type() != Item::FIELD_ITEM) @@ -6845,8 +6850,14 @@ find_order_in_list(THD *thd,TABLE_LIST *tables,ORDER *order,List<Item> &fields, return 0; } order->in_field_list=0; + /* Allow lookup in select's item_list to find aliased fields */ + thd->lex.select_lex.is_item_list_lookup= 1; if ((*order->item)->fix_fields(thd,tables) || thd->fatal_error) + { + thd->lex.select_lex.is_item_list_lookup= 0; return 1; // Wrong field + } + thd->lex.select_lex.is_item_list_lookup= 0; all_fields.push_front(*order->item); // Add new field to field list order->item=(Item**) all_fields.head_ref(); return 0; diff --git a/sql/sql_table.cc b/sql/sql_table.cc index 4c269e6830f..987d12ccb40 100644 --- a/sql/sql_table.cc +++ b/sql/sql_table.cc @@ -179,7 +179,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists, { char *db=table->db; uint flags; - mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL); + mysql_ha_flush(thd, table, MYSQL_HA_CLOSE_FINAL, TRUE); if (!close_temporary_table(thd, db, table->real_name)) { tmp_table_deleted=1; @@ -1239,7 +1239,7 @@ static int mysql_admin_table(THD* thd, TABLE_LIST* tables, if (send_fields(thd, field_list, 1)) DBUG_RETURN(-1); - mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL); + mysql_ha_flush(thd, tables, MYSQL_HA_CLOSE_FINAL, FALSE); for (table = tables; table; table = table->next) { char table_name[NAME_LEN*2+2]; @@ -1500,7 +1500,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name, } used_fields=create_info->used_fields; - mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL); + mysql_ha_flush(thd, table_list, MYSQL_HA_CLOSE_FINAL, FALSE); if (!(table=open_ltable(thd,table_list,TL_WRITE_ALLOW_READ))) DBUG_RETURN(-1); |