summaryrefslogtreecommitdiff
path: root/sql/sql_handler.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/sql_handler.cc')
-rw-r--r--sql/sql_handler.cc192
1 files changed, 163 insertions, 29 deletions
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index fcc56cbf9c9..56c1b0a1b51 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -43,7 +43,9 @@
thd->handler_tables=tmp; }
static TABLE **find_table_ptr_by_name(THD *thd,const char *db,
- const char *table_name, bool is_alias);
+ const char *table_name,
+ bool is_alias, bool dont_lock,
+ bool *was_flushed);
int mysql_ha_open(THD *thd, TABLE_LIST *tables)
{
@@ -66,24 +68,61 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables)
return 0;
}
-int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok)
+
+/*
+ Close a HANDLER table.
+
+ SYNOPSIS
+ mysql_ha_close()
+ thd Thread identifier.
+ tables A list of tables with the first entry to close.
+ dont_send_ok Suppresses the commands' ok message and
+ error message and error return.
+ dont_lock Suppresses the normal locking of LOCK_open.
+
+ DESCRIPTION
+ Though this function takes a list of tables, only the first list entry
+ will be closed. Broadcasts a COND_refresh condition.
+ If mysql_ha_close() is not called from the parser, 'dont_send_ok'
+ must be set.
+ If the caller did already lock LOCK_open, it must set 'dont_lock'.
+
+ IMPLEMENTATION
+ find_table_ptr_by_name() closes the table, if a FLUSH TABLE is outstanding.
+ It returns a NULL pointer in this case, but flags the situation in
+ 'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages
+ is suppressed.
+
+ RETURN
+ 0 ok
+ -1 error
+*/
+
+int mysql_ha_close(THD *thd, TABLE_LIST *tables,
+ bool dont_send_ok, bool dont_lock, bool no_alias)
{
- TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->alias, 1);
+ TABLE **table_ptr;
+ bool was_flushed;
- if (*ptr)
+ table_ptr= find_table_ptr_by_name(thd, tables->db, tables->alias,
+ !no_alias, dont_lock, &was_flushed);
+ if (*table_ptr)
{
- VOID(pthread_mutex_lock(&LOCK_open));
- if (close_thread_table(thd, ptr))
+ (*table_ptr)->file->ha_index_or_rnd_end();
+ if (!dont_lock)
+ 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));
+ if (!dont_lock)
+ VOID(pthread_mutex_unlock(&LOCK_open));
}
- else
+ else if (!was_flushed && !dont_send_ok)
{
- my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
- tables->alias, "HANDLER");
+ my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
+ tables->alias, "HANDLER");
return -1;
}
if (!dont_send_ok)
@@ -91,13 +130,65 @@ int mysql_ha_close(THD *thd, TABLE_LIST *tables, bool dont_send_ok)
return 0;
}
-int mysql_ha_closeall(THD *thd, TABLE_LIST *tables)
+
+/*
+ Close a list of HANDLER tables.
+
+ SYNOPSIS
+ mysql_ha_close_list()
+ thd Thread identifier.
+ tables The list of tables to close. If NULL,
+ close all HANDLER tables.
+ flushed Close only tables which are marked flushed.
+ Used only if tables is NULL.
+
+ DESCRIPTION
+ The list of HANDLER tables may be NULL, in which case all HANDLER
+ tables are closed. Broadcasts a COND_refresh condition, for
+ every table closed. If 'tables' is NULL and 'flushed' is set,
+ all HANDLER tables marked for flush are closed.
+ The caller must lock LOCK_open.
+
+ IMPLEMENTATION
+ find_table_ptr_by_name() closes the table, if it is marked for flush.
+ It returns a NULL pointer in this case, but flags the situation in
+ 'was_flushed'. In that case the normal ER_UNKNOWN_TABLE error messages
+ is suppressed.
+
+ RETURN
+ 0 ok
+*/
+
+int mysql_ha_close_list(THD *thd, TABLE_LIST *tables, bool flushed)
{
- TABLE **ptr=find_table_ptr_by_name(thd, tables->db, tables->real_name, 0);
- if (*ptr && close_thread_table(thd, ptr))
+ TABLE_LIST *tl_item;
+ TABLE **table_ptr;
+
+ if (tables)
{
- /* Tell threads waiting for refresh that something has happened */
- VOID(pthread_cond_broadcast(&COND_refresh));
+ for (tl_item= tables ; tl_item; tl_item= tl_item->next)
+ {
+ mysql_ha_close(thd, tl_item, /*dont_send_ok*/ 1,
+ /*dont_lock*/ 1, /*no_alias*/ 1);
+ }
+ }
+ else
+ {
+ table_ptr= &(thd->handler_tables);
+ while (*table_ptr)
+ {
+ if (! flushed || ((*table_ptr)->version != refresh_version))
+ {
+ (*table_ptr)->file->ha_index_or_rnd_end();
+ if (close_thread_table(thd, table_ptr))
+ {
+ /* Tell threads waiting for refresh that something has happened */
+ VOID(pthread_cond_broadcast(&COND_refresh));
+ }
+ continue;
+ }
+ table_ptr= &((*table_ptr)->next);
+ }
}
return 0;
}
@@ -112,7 +203,10 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
ha_rows select_limit,ha_rows offset_limit)
{
int err, keyno=-1;
- TABLE *table=*find_table_ptr_by_name(thd, tables->db, tables->alias, 1);
+ bool was_flushed;
+ TABLE *table= *find_table_ptr_by_name(thd, tables->db, tables->alias,
+ /*is_alias*/ 1, /*dont_lock*/ 0,
+ &was_flushed);
if (!table)
{
my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
@@ -136,7 +230,8 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
keyname,tables->alias);
return -1;
}
- table->file->index_init(keyno);
+ table->file->ha_index_or_rnd_end();
+ table->file->ha_index_init(keyno);
}
List<Item> list;
@@ -148,8 +243,8 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
uint num_rows;
byte *key;
uint key_len;
- LINT_INIT(key);
- LINT_INIT(key_len);
+ LINT_INIT(key);
+ LINT_INIT(key_len);
it++; // Skip first NULL field
@@ -180,7 +275,8 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
err=table->file->index_first(table->record[0]);
else
{
- if (!(err=table->file->rnd_init(1)))
+ table->file->ha_index_or_rnd_end();
+ if (!(err=table->file->ha_rnd_init(1)))
err=table->file->rnd_next(table->record[0]);
}
mode=RNEXT;
@@ -291,17 +387,51 @@ err0:
}
+/*
+ Find a HANDLER table by name.
+
+ SYNOPSIS
+ find_table_ptr_by_name()
+ thd Thread identifier.
+ db Database (schema) name.
+ table_name Table name ;-).
+ is_alias Table name may be an alias name.
+ dont_lock Suppresses the normal locking of LOCK_open.
+
+ DESCRIPTION
+ Find the table 'db'.'table_name' in the list of HANDLER tables of the
+ thread 'thd'. If the table has been marked by FLUSH TABLE(S), close it,
+ flag this situation in '*was_flushed' and broadcast a COND_refresh
+ condition.
+ An empty database (schema) name matches all database (schema) names.
+ If the caller did already lock LOCK_open, it must set 'dont_lock'.
+
+ IMPLEMENTATION
+ Just in case that the table is twice in 'thd->handler_tables' (!?!),
+ the loop does not break when the table was flushed. If another table
+ by that name was found and not flushed, '*was_flushed' is cleared again,
+ since a pointer to an open HANDLER table is returned.
+
+ RETURN
+ *was_flushed Table has been closed due to FLUSH TABLE.
+ NULL A HANDLER Table by that name does not exist (any more).
+ != NULL Pointer to the TABLE structure.
+*/
+
static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
- const char *table_name, bool is_alias)
+ const char *table_name,
+ bool is_alias, bool dont_lock,
+ bool *was_flushed)
{
int dblen;
- TABLE **ptr;
+ TABLE **table_ptr;
DBUG_ASSERT(db);
dblen= strlen(db);
- ptr= &(thd->handler_tables);
+ table_ptr= &(thd->handler_tables);
+ *was_flushed= FALSE;
- for (TABLE *table= *ptr; table ; table= *ptr)
+ for (TABLE *table= *table_ptr; table ; table= *table_ptr)
{
if ((db == any_db || !memcmp(table->table_cache_key, db, dblen)) &&
!my_strcasecmp(system_charset_info,
@@ -310,18 +440,22 @@ static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
{
if (table->version != refresh_version)
{
- VOID(pthread_mutex_lock(&LOCK_open));
- if (close_thread_table(thd, ptr))
+ if (!dont_lock)
+ 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));
+ if (!dont_lock)
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ *was_flushed= TRUE;
continue;
}
+ *was_flushed= FALSE;
break;
}
- ptr= &(table->next);
+ table_ptr= &(table->next);
}
- return ptr;
+ return table_ptr;
}