summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
Diffstat (limited to 'sql')
-rw-r--r--sql/item.cc11
-rw-r--r--sql/mysql_priv.h3
-rw-r--r--sql/sql_base.cc7
-rw-r--r--sql/sql_class.cc2
-rw-r--r--sql/sql_handler.cc49
-rw-r--r--sql/sql_lex.cc1
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_select.cc17
-rw-r--r--sql/sql_table.cc6
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);