summaryrefslogtreecommitdiff
path: root/sql/sql_handler.cc
diff options
context:
space:
mode:
authormonty@mysql.com <>2004-10-06 19:14:33 +0300
committermonty@mysql.com <>2004-10-06 19:14:33 +0300
commit62f3cd6a31d3c1ffe7ad17d9de862a3c0859f56a (patch)
tree4e2cfa6a6a8032773454e22aa802b2798b2935b8 /sql/sql_handler.cc
parent96458f8f64641d5b974a17733af8c709b513bfe0 (diff)
parent0944bed7fcb59fb38230a750bd820a22b3b6b476 (diff)
downloadmariadb-git-62f3cd6a31d3c1ffe7ad17d9de862a3c0859f56a.tar.gz
Merge with 4.0 for 4.1 release
Noteworthy: - New HANDLER code - New multi-update-grant-check code - Table lock code in ha_innodb.cc was not applied
Diffstat (limited to 'sql/sql_handler.cc')
-rw-r--r--sql/sql_handler.cc644
1 files changed, 460 insertions, 184 deletions
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 56c1b0a1b51..1e50e1e571e 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -1,5 +1,4 @@
-/* Copyright (C) 2000-2003 MySQL AB
-
+/* Copyright (C) 2000-2004 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
@@ -17,9 +16,6 @@
/* HANDLER ... commands - direct access to ISAM */
-#include "mysql_priv.h"
-#include "sql_select.h"
-
/* TODO:
HANDLER blabla OPEN [ AS foobar ] [ (column-list) ]
@@ -37,190 +33,410 @@
all the sql_alloc'ed memory. It's harder to work around...
*/
+/*
+ There are two containers holding information about open handler tables.
+ The first is 'thd->handler_tables'. It is a linked list of TABLE objects.
+ It is used like 'thd->open_tables' in the table cache. The trick is to
+ exchange these two lists during open and lock of tables. Thus the normal
+ table cache code can be used.
+ The second container is a HASH. It holds objects of the type TABLE_LIST.
+ Despite its name, no lists of tables but only single structs are hashed
+ (the 'next' pointer is always NULL). The reason for theis second container
+ is, that we want handler tables to survive FLUSH TABLE commands. A table
+ affected by FLUSH TABLE must be closed so that other threads are not
+ blocked by handler tables still in use. Since we use the normal table cache
+ functions with 'thd->handler_tables', the closed tables are removed from
+ this list. Hence we need the original open information for the handler
+ table in the case that it is used again. This information is handed over
+ to mysql_ha_open() as a TABLE_LIST. So we store this information in the
+ second container, where it is not affected by FLUSH TABLE. The second
+ container is implemented as a hash for performance reasons. Consequently,
+ we use it not only for re-opening a handler table, but also for the
+ HANDLER ... READ commands. For this purpose, we store a pointer to the
+ TABLE structure (in the first container) in the TBALE_LIST object in the
+ second container. When the table is flushed, the pointer is cleared.
+*/
+
+#include "mysql_priv.h"
+#include "sql_select.h"
+#include <assert.h>
+
+#define HANDLER_TABLES_HASH_SIZE 120
+
+static enum enum_ha_read_modes rkey_to_rnext[]=
+ { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV };
+
#define HANDLER_TABLES_HACK(thd) { \
TABLE *tmp=thd->open_tables; \
thd->open_tables=thd->handler_tables; \
thd->handler_tables=tmp; }
-static TABLE **find_table_ptr_by_name(THD *thd,const char *db,
- const char *table_name,
- bool is_alias, bool dont_lock,
- bool *was_flushed);
+static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, int mode_flags);
+
+
+/*
+ Get hash key and hash key length.
+
+ SYNOPSIS
+ mysql_ha_hash_get_key()
+ tables Pointer to the hash object.
+ key_len_p (out) Pointer to the result for key length.
+ first Unused.
+
+ DESCRIPTION
+ The hash object is an TABLE_LIST struct.
+ The hash key is the alias name.
+ The hash key length is the alias name length plus one for the
+ terminateing NUL character.
+
+ RETURN
+ Pointer to the TABLE_LIST struct.
+*/
-int mysql_ha_open(THD *thd, TABLE_LIST *tables)
+static char *mysql_ha_hash_get_key(TABLE_LIST *tables, uint *key_len_p,
+ my_bool first __attribute__((unused)))
{
- HANDLER_TABLES_HACK(thd);
- uint counter;
- int err=open_tables(thd, tables, &counter);
- HANDLER_TABLES_HACK(thd);
- if (err)
- return -1;
+ *key_len_p= strlen(tables->alias) + 1 ; /* include '\0' in comparisons */
+ return tables->alias;
+}
- // there can be only one table in *tables
- if (!(tables->table->file->table_flags() & HA_CAN_SQL_HANDLER))
- {
- my_printf_error(ER_ILLEGAL_HA,ER(ER_ILLEGAL_HA),MYF(0), tables->alias);
- mysql_ha_close(thd, tables,1);
- return -1;
- }
- send_ok(thd);
- return 0;
+/*
+ Free an hash object.
+
+ SYNOPSIS
+ mysql_ha_hash_free()
+ tables Pointer to the hash object.
+
+ DESCRIPTION
+ The hash object is an TABLE_LIST struct.
+
+ RETURN
+ Nothing
+*/
+
+static void mysql_ha_hash_free(TABLE_LIST *tables)
+{
+ my_free((char*) tables, MYF(0));
}
/*
- Close a HANDLER table.
+ Open a HANDLER table.
SYNOPSIS
- mysql_ha_close()
+ mysql_ha_open()
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.
+ tables A list of tables with the first entry to open.
+ reopen Re-open a previously opened handler table.
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.
+ will be opened.
+ 'reopen' is set when a handler table is to be re-opened. In this case,
+ 'tables' is the pointer to the hashed TABLE_LIST object which has been
+ saved on the original open.
+ 'reopen' is also used to suppress the sending of an 'ok' message or
+ error messages.
RETURN
- 0 ok
- -1 error
+ 0 ok
+ != 0 error
*/
-int mysql_ha_close(THD *thd, TABLE_LIST *tables,
- bool dont_send_ok, bool dont_lock, bool no_alias)
+int mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
{
- TABLE **table_ptr;
- bool was_flushed;
-
- table_ptr= find_table_ptr_by_name(thd, tables->db, tables->alias,
- !no_alias, dont_lock, &was_flushed);
- if (*table_ptr)
+ TABLE_LIST *hash_tables;
+ char *db, *name, *alias;
+ uint dblen, namelen, aliaslen, counter;
+ int err;
+ DBUG_ENTER("mysql_ha_open");
+ DBUG_PRINT("enter",("mysql_ha_open: '%s'.'%s' as '%s' reopen %d",
+ tables->db, tables->real_name, tables->alias, reopen));
+
+ if (! hash_inited(&thd->handler_tables_hash))
+ {
+ /*
+ HASH entries are of type TABLE_LIST.
+ */
+ if (hash_init(&thd->handler_tables_hash, HANDLER_TABLES_HASH_SIZE, 0, 0,
+ (hash_get_key) mysql_ha_hash_get_key,
+ (hash_free_key) mysql_ha_hash_free, 0))
+ goto err;
+ }
+ else if (! reopen) /* Otherwise we have 'tables' already. */
{
- (*table_ptr)->file->ha_index_or_rnd_end();
- if (!dont_lock)
- VOID(pthread_mutex_lock(&LOCK_open));
- if (close_thread_table(thd, table_ptr))
+ if (hash_search(&thd->handler_tables_hash, (byte*) tables->alias,
+ strlen(tables->alias) + 1))
{
- /* Tell threads waiting for refresh that something has happened */
- VOID(pthread_cond_broadcast(&COND_refresh));
+ DBUG_PRINT("info",("mysql_ha_open: duplicate '%s'", tables->alias));
+ if (! reopen)
+ my_printf_error(ER_NONUNIQ_TABLE, ER(ER_NONUNIQ_TABLE),
+ MYF(0), tables->alias);
+ goto err;
}
- if (!dont_lock)
- VOID(pthread_mutex_unlock(&LOCK_open));
}
- else if (!was_flushed && !dont_send_ok)
+
+ /*
+ open_tables() will set 'tables->table' if successful.
+ It must be NULL for a real open when calling open_tables().
+ */
+ DBUG_ASSERT(! tables->table);
+ HANDLER_TABLES_HACK(thd);
+ err=open_tables(thd, tables, &counter);
+ HANDLER_TABLES_HACK(thd);
+ if (err)
+ goto err;
+
+ /* There can be only one table in '*tables'. */
+ if (! (tables->table->file->table_flags() & HA_CAN_SQL_HANDLER))
+ {
+ if (! reopen)
+ my_printf_error(ER_ILLEGAL_HA,ER(ER_ILLEGAL_HA),MYF(0), tables->alias);
+ mysql_ha_close(thd, tables);
+ goto err;
+ }
+
+ if (! reopen)
{
- my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
- tables->alias, "HANDLER");
- return -1;
+ /* copy the TABLE_LIST struct */
+ dblen= strlen(tables->db) + 1;
+ namelen= strlen(tables->real_name) + 1;
+ aliaslen= strlen(tables->alias) + 1;
+ if (!(my_multi_malloc(MYF(MY_WME),
+ &hash_tables, sizeof(*hash_tables),
+ &db, dblen,
+ &name, namelen,
+ &alias, aliaslen,
+ NullS)))
+ {
+ DBUG_PRINT("exit",("mysql_ha_open: malloc ERROR"));
+ goto err;
+ }
+ /* structure copy */
+ *hash_tables= *tables;
+ hash_tables->db= db;
+ hash_tables->real_name= name;
+ hash_tables->alias= alias;
+ memcpy(hash_tables->db, tables->db, dblen);
+ memcpy(hash_tables->real_name, tables->real_name, namelen);
+ memcpy(hash_tables->alias, tables->alias, aliaslen);
+
+ /* add to hash */
+ if (hash_insert(&thd->handler_tables_hash, (byte*) hash_tables))
+ {
+ mysql_ha_close(thd, tables);
+ goto err;
+ }
}
- if (!dont_send_ok)
+
+ if (! reopen)
send_ok(thd);
- return 0;
+ DBUG_PRINT("exit",("mysql_ha_open: OK"));
+ DBUG_RETURN(0);
+
+err:
+ DBUG_PRINT("exit",("mysql_ha_open: ERROR"));
+ DBUG_RETURN(-1);
}
/*
- Close a list of HANDLER tables.
+ Close a HANDLER table.
SYNOPSIS
- mysql_ha_close_list()
+ mysql_ha_close()
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.
+ tables A list of tables with the first entry to close.
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.
+ Though this function takes a list of tables, only the first list entry
+ will be closed. Broadcasts a COND_refresh condition.
RETURN
- 0 ok
+ 0 ok
+ != 0 error
*/
-int mysql_ha_close_list(THD *thd, TABLE_LIST *tables, bool flushed)
+int mysql_ha_close(THD *thd, TABLE_LIST *tables)
{
- TABLE_LIST *tl_item;
+ TABLE_LIST *hash_tables;
TABLE **table_ptr;
-
- if (tables)
+ bool was_flushed= FALSE;
+ bool not_opened;
+ DBUG_ENTER("mysql_ha_close");
+ DBUG_PRINT("enter",("mysql_ha_close: '%s'.'%s' as '%s'",
+ tables->db, tables->real_name, tables->alias));
+
+ if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
+ (byte*) tables->alias,
+ strlen(tables->alias) + 1)))
{
- for (tl_item= tables ; tl_item; tl_item= tl_item->next)
+ /*
+ Though we could take the table pointer from hash_tables->table,
+ we must follow the thd->handler_tables chain anyway, 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 != hash_tables->table);
+ table_ptr= &(*table_ptr)->next);
+
+#if MYSQL_VERSION_ID < 40100
+ if (*tables->db && strcmp(hash_tables->db, tables->db))
{
- mysql_ha_close(thd, tl_item, /*dont_send_ok*/ 1,
- /*dont_lock*/ 1, /*no_alias*/ 1);
+ DBUG_PRINT("info",("mysql_ha_close: wrong db"));
+ hash_tables= NULL;
}
- }
- else
- {
- table_ptr= &(thd->handler_tables);
- while (*table_ptr)
+ else
+#endif
{
- if (! flushed || ((*table_ptr)->version != refresh_version))
+ if (*table_ptr)
{
- (*table_ptr)->file->ha_index_or_rnd_end();
+ table_ptr->file->ha_index_or_rnd_end();
+ 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));
}
- continue;
+ VOID(pthread_mutex_unlock(&LOCK_open));
}
- table_ptr= &((*table_ptr)->next);
+
+ hash_delete(&thd->handler_tables_hash, (byte*) hash_tables);
}
}
- return 0;
+
+ if (! hash_tables)
+ {
+#if MYSQL_VERSION_ID < 40100
+ char buff[MAX_DBKEY_LENGTH];
+ if (*tables->db)
+ strxnmov(buff, sizeof(buff), tables->db, ".", tables->real_name, NullS);
+ else
+ strncpy(buff, tables->alias, sizeof(buff));
+ my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
+ buff, "HANDLER");
+#else
+ my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
+ tables->alias, "HANDLER");
+#endif
+ DBUG_PRINT("exit",("mysql_ha_close: ERROR"));
+ DBUG_RETURN(-1);
+ }
+
+ send_ok(thd);
+ DBUG_PRINT("exit",("mysql_ha_close: OK"));
+ DBUG_RETURN(0);
}
-static enum enum_ha_read_modes rkey_to_rnext[]=
- { RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV };
+/*
+ Read from a HANDLER table.
+
+ SYNOPSIS
+ mysql_ha_read()
+ thd Thread identifier.
+ tables A list of tables with the first entry to read.
+ mode
+ keyname
+ key_expr
+ ha_rkey_mode
+ cond
+ select_limit
+ offset_limit
+ RETURN
+ 0 ok
+ != 0 error
+*/
+
int mysql_ha_read(THD *thd, TABLE_LIST *tables,
enum enum_ha_read_modes mode, char *keyname, List<Item> *key_expr,
enum ha_rkey_function ha_rkey_mode, Item *cond,
ha_rows select_limit,ha_rows offset_limit)
{
- int err, keyno=-1;
- bool was_flushed;
- TABLE *table= *find_table_ptr_by_name(thd, tables->db, tables->alias,
- /*is_alias*/ 1, /*dont_lock*/ 0,
- &was_flushed);
+ TABLE_LIST *hash_tables;
+ TABLE *table;
+ MYSQL_LOCK *lock;
+ List<Item> list;
+ Protocol *protocol= thd->protocol;
+ char buff[MAX_FIELD_WIDTH];
+ String buffer(buff, sizeof(buff), system_charset_info);
+ int err, keyno= -1;
+ uint num_rows;
+ byte *key;
+ uint key_len;
+ bool was_flushed;
+ DBUG_ENTER("mysql_ha_read");
+ DBUG_PRINT("enter",("mysql_ha_read: '%s'.'%s' as '%s'",
+ tables->db, tables->real_name, tables->alias));
+
+ LINT_INIT(key);
+ LINT_INIT(key_len);
+
+ list.push_front(new Item_field(NULL,NULL,"*"));
+ List_iterator<Item> it(list);
+ it++;
+
+ if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
+ (byte*) tables->alias,
+ strlen(tables->alias) + 1)))
+ {
+ table= hash_tables->table;
+ DBUG_PRINT("info",("mysql_ha_read: found in hash '%s'.'%s' as '%s' tab %p",
+ hash_tables->db, hash_tables->real_name,
+ hash_tables->alias, table));
+ if (!table)
+ {
+ /*
+ The handler table has been closed. Re-open it.
+ */
+ if (mysql_ha_open(thd, hash_tables, 1))
+ {
+ DBUG_PRINT("exit",("mysql_ha_read: reopen failed"));
+ goto err0;
+ }
+
+ table= hash_tables->table;
+ DBUG_PRINT("info",("mysql_ha_read: re-opened '%s'.'%s' as '%s' tab %p",
+ hash_tables->db, hash_tables->real_name,
+ hash_tables->alias, table));
+ }
+
+#if MYSQL_VERSION_ID < 40100
+ if (*tables->db && strcmp(table->table_cache_key, tables->db))
+ {
+ DBUG_PRINT("info",("mysql_ha_read: wrong db"));
+ table= NULL;
+ }
+#endif
+ }
+ else
+ table= NULL;
+
if (!table)
{
- my_printf_error(ER_UNKNOWN_TABLE,ER(ER_UNKNOWN_TABLE),MYF(0),
- tables->alias,"HANDLER");
- return -1;
+#if MYSQL_VERSION_ID < 40100
+ char buff[MAX_DBKEY_LENGTH];
+ if (*tables->db)
+ strxnmov(buff, sizeof(buff), tables->db, ".", tables->real_name, NullS);
+ else
+ strncpy(buff, tables->alias, sizeof(buff));
+ my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
+ buff, "HANDLER");
+#else
+ my_printf_error(ER_UNKNOWN_TABLE, ER(ER_UNKNOWN_TABLE), MYF(0),
+ tables->alias, "HANDLER");
+#endif
+ goto err0;
}
tables->table=table;
if (cond && (cond->fix_fields(thd, tables, &cond) || cond->check_cols(1)))
- return -1;
-
- /* InnoDB needs to know that this table handle is used in the HANDLER */
+ goto err0;
- table->file->init_table_handle_for_HANDLER();
+ table->file->init_table_handle_for_HANDLER(); // Only InnoDB requires it
if (keyname)
{
@@ -228,34 +444,22 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
{
my_printf_error(ER_KEY_DOES_NOT_EXITS,ER(ER_KEY_DOES_NOT_EXITS),MYF(0),
keyname,tables->alias);
- return -1;
+ goto err0;
}
table->file->ha_index_or_rnd_end();
table->file->ha_index_init(keyno);
}
- List<Item> list;
- list.push_front(new Item_field(NULL,NULL,"*"));
- List_iterator<Item> it(list);
- Protocol *protocol= thd->protocol;
- char buff[MAX_FIELD_WIDTH];
- String buffer(buff, sizeof(buff), system_charset_info);
- uint num_rows;
- byte *key;
- uint key_len;
- LINT_INIT(key);
- LINT_INIT(key_len);
-
- it++; // Skip first NULL field
-
- insert_fields(thd,tables,tables->db,tables->alias,&it);
+ if (insert_fields(thd,tables,tables->db,tables->alias,&it))
+ goto err0;
select_limit+=offset_limit;
protocol->send_fields(&list,1);
HANDLER_TABLES_HACK(thd);
- MYSQL_LOCK *lock=mysql_lock_tables(thd,&tables->table,1);
+ lock= mysql_lock_tables(thd, &tables->table, 1);
HANDLER_TABLES_HACK(thd);
+
if (!lock)
goto err0; // mysql_lock_tables() printed error message already
@@ -378,84 +582,156 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
}
ok:
mysql_unlock_tables(thd,lock);
- send_eof(thd);
- return 0;
+ send_eof(&thd->net);
+ DBUG_PRINT("exit",("mysql_ha_read: OK"));
+ DBUG_RETURN(0);
err:
mysql_unlock_tables(thd,lock);
err0:
- return -1;
+ DBUG_PRINT("exit",("mysql_ha_read: ERROR"));
+ DBUG_RETURN(-1);
}
/*
- Find a HANDLER table by name.
+ Flush (close) a list of HANDLER tables.
SYNOPSIS
- find_table_ptr_by_name()
+ mysql_ha_flush()
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.
+ tables The list of tables to close. If NULL,
+ close all HANDLER tables [marked as flushed].
+ mode_flags MYSQL_HA_CLOSE_FINAL finally close the table.
+ MYSQL_HA_REOPEN_ON_USAGE mark for reopen.
+ MYSQL_HA_FLUSH_ALL flush all tables, not only
+ those marked for flush.
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.
+ The list of HANDLER tables may be NULL, in which case all HANDLER
+ tables are closed (if MYSQL_HA_FLUSH_ALL) is set.
+ 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,
+ we compare real table names, not aliases. Hence, database names matter.
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.
+ 0 ok
*/
-static TABLE **find_table_ptr_by_name(THD *thd, const char *db,
- const char *table_name,
- bool is_alias, bool dont_lock,
- bool *was_flushed)
+int mysql_ha_flush(THD *thd, TABLE_LIST *tables, int mode_flags)
{
- int dblen;
- TABLE **table_ptr;
-
- DBUG_ASSERT(db);
- dblen= strlen(db);
- table_ptr= &(thd->handler_tables);
- *was_flushed= FALSE;
+ TABLE_LIST **tmp_tables_p;
+ TABLE_LIST *tmp_tables;
+ TABLE **table_ptr;
+ bool was_flushed;
+ DBUG_ENTER("mysql_ha_flush");
+ DBUG_PRINT("enter",("mysql_ha_flush: tables %p mode_flags 0x%02x",
+ tables, mode_flags));
- for (TABLE *table= *table_ptr; table ; table= *table_ptr)
+ if (tables)
{
- if ((db == any_db || !memcmp(table->table_cache_key, db, dblen)) &&
- !my_strcasecmp(system_charset_info,
- (is_alias ? table->table_name : table->real_name),
- table_name))
+ /* Close all tables in the list. */
+ for (tmp_tables= tables ; tmp_tables; tmp_tables= tmp_tables->next)
{
- if (table->version != refresh_version)
+ DBUG_PRINT("info",("mysql_ha_flush: in tables list '%s'.'%s' as '%s'",
+ tmp_tables->db, tmp_tables->real_name,
+ tmp_tables->alias));
+ /* Close all currently open handler tables with the same base table. */
+ table_ptr= &(thd->handler_tables);
+ while (*table_ptr)
{
- if (!dont_lock)
- VOID(pthread_mutex_lock(&LOCK_open));
- if (close_thread_table(thd, table_ptr))
+ if ((! *tmp_tables->db ||
+ ! my_strcasecmp((*table_ptr)->table_cache_key, tmp_tables->db)) &&
+ ! my_strcasecmp((*table_ptr)->real_name, tmp_tables->real_name))
{
- /* Tell threads waiting for refresh that something has happened */
- VOID(pthread_cond_broadcast(&COND_refresh));
+ DBUG_PRINT("info",("mysql_ha_flush: *table_ptr '%s'.'%s' as '%s'",
+ (*table_ptr)->table_cache_key,
+ (*table_ptr)->real_name,
+ (*table_ptr)->table_name));
+ mysql_ha_flush_table(thd, table_ptr, mode_flags);
+ continue;
}
- if (!dont_lock)
- VOID(pthread_mutex_unlock(&LOCK_open));
- *was_flushed= TRUE;
+ table_ptr= &(*table_ptr)->next;
+ }
+ /* end of handler_tables list */
+ }
+ /* end of flush tables list */
+ }
+ else
+ {
+ /* Close all currently open tables [which are marked for flush]. */
+ table_ptr= &(thd->handler_tables);
+ while (*table_ptr)
+ {
+ if ((mode_flags & MYSQL_HA_FLUSH_ALL) ||
+ ((*table_ptr)->version != refresh_version))
+ {
+ mysql_ha_flush_table(thd, table_ptr, mode_flags);
continue;
}
- *was_flushed= FALSE;
- break;
+ table_ptr= &(*table_ptr)->next;
+ }
+ }
+
+ DBUG_PRINT("exit",("mysql_ha_flush: OK"));
+ DBUG_RETURN(0);
+}
+
+/*
+ Flush (close) a table.
+
+ SYNOPSIS
+ mysql_ha_flush_table()
+ thd Thread identifier.
+ table The table to close.
+ mode_flags MYSQL_HA_CLOSE_FINAL finally close the table.
+ MYSQL_HA_REOPEN_ON_USAGE mark for reopen.
+
+ DESCRIPTION
+ Broadcasts a COND_refresh condition, for every table closed.
+ The caller must lock LOCK_open.
+
+ RETURN
+ 0 ok
+*/
+
+static int mysql_ha_flush_table(THD *thd, TABLE **table_ptr, int mode_flags)
+{
+ TABLE_LIST *hash_tables;
+ TABLE *table= *table_ptr;
+ bool was_flushed;
+ DBUG_ENTER("mysql_ha_flush_table");
+ DBUG_PRINT("info",("mysql_ha_flush_table: '%s'.'%s' as '%s' flags 0x%02x",
+ table->table_cache_key, table->real_name,
+ table->table_name, mode_flags));
+
+ if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
+ (*table_ptr)->table_name,
+ strlen((*table_ptr)->table_name) + 1)))
+ {
+ if (! (mode_flags & MYSQL_HA_REOPEN_ON_USAGE))
+ {
+ /* This is a final close. Remove from hash. */
+ hash_delete(&thd->handler_tables_hash, (byte*) hash_tables);
+ }
+ else
+ {
+ /* Mark table as closed, ready for re-open. */
+ hash_tables->table= NULL;
}
- table_ptr= &(table->next);
+ }
+
+ 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));
}
- return table_ptr;
+
+ DBUG_PRINT("exit",("mysql_ha_flush_table: OK"));
+ DBUG_RETURN(0);
}