1
/* Copyright (C) 2000-2004 MySQL AB
2
This program is free software; you can redistribute it and/or modify
3
it under the terms of the GNU General Public License as published by
4
the Free Software Foundation; version 2 of the License.
6
This program is distributed in the hope that it will be useful,
7
but WITHOUT ANY WARRANTY; without even the implied warranty of
8
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
9
GNU General Public License for more details.
11
You should have received a copy of the GNU General Public License
12
along with this program; if not, write to the Free Software
13
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
16
/* HANDLER ... commands - direct access to ISAM */
19
HANDLER blabla OPEN [ AS foobar ] [ (column-list) ]
21
the most natural (easiest, fastest) way to do it is to
22
compute List<Item> field_list not in mysql_ha_read
23
but in mysql_ha_open, and then store it in Table structure.
25
The problem here is that mysql_parse calls free_item to free all the
26
items allocated at the end of every query. The workaround would to
27
keep two item lists per Session - normal free_list and handler_items.
28
The second is to be freeed only on thread end. mysql_ha_open should
29
then do { handler_items=concat(handler_items, free_list); free_list=0; }
31
But !!! do_command calls free_root at the end of every query and frees up
32
all the sql_alloc'ed memory. It's harder to work around...
36
There are two containers holding information about open handler tables.
37
The first is 'session->handler_tables'. It is a linked list of Table objects.
38
It is used like 'session->open_tables' in the table cache. The trick is to
39
exchange these two lists during open and lock of tables. Thus the normal
40
table cache code can be used.
41
The second container is a HASH. It holds objects of the type TableList.
42
Despite its name, no lists of tables but only single structs are hashed
43
(the 'next' pointer is always NULL). The reason for theis second container
44
is, that we want handler tables to survive FLUSH Table commands. A table
45
affected by FLUSH Table must be closed so that other threads are not
46
blocked by handler tables still in use. Since we use the normal table cache
47
functions with 'session->handler_tables', the closed tables are removed from
48
this list. Hence we need the original open information for the handler
49
table in the case that it is used again. This information is handed over
50
to mysql_ha_open() as a TableList. So we store this information in the
51
second container, where it is not affected by FLUSH Table. The second
52
container is implemented as a hash for performance reasons. Consequently,
53
we use it not only for re-opening a handler table, but also for the
54
HANDLER ... READ commands. For this purpose, we store a pointer to the
55
Table structure (in the first container) in the TBALE_LIST object in the
56
second container. When the table is flushed, the pointer is cleared.
59
#include <drizzled/server_includes.h>
60
#include <drizzled/sql_select.h>
61
#include <drizzled/error.h>
62
#include <drizzled/sql_base.h>
63
#include <drizzled/lock.h>
67
Close a HANDLER table.
69
@param session Thread identifier.
70
@param tables A list of tables with the first entry to close.
71
@param is_locked If LOCK_open is locked.
73
@note Though this function takes a list of tables, only the first list entry
75
@note Broadcasts refresh if it closed a table with old version.
78
static void mysql_ha_close_table(Session *session, TableList *tables,
84
Though we could take the table pointer from hash_tables->table,
85
we must follow the session->handler_tables chain anyway, as we need the
86
address of the 'next' pointer referencing this table
87
for close_thread_table().
89
for (table_ptr= &(session->handler_tables);
90
*table_ptr && (*table_ptr != tables->table);
91
table_ptr= &(*table_ptr)->next)
96
(*table_ptr)->file->ha_index_or_rnd_end();
98
pthread_mutex_lock(&LOCK_open);
99
if (close_thread_table(session, table_ptr))
101
/* Tell threads waiting for refresh that something has happened */
105
pthread_mutex_unlock(&LOCK_open);
107
else if (tables->table)
109
/* Must be a temporary table */
110
Table *table= tables->table;
111
table->file->ha_index_or_rnd_end();
112
table->query_id= session->query_id;
113
table->open_by_handler= 0;
119
Close a HANDLER table by alias or table name
123
session Thread identifier.
124
tables A list of tables with the first entry to close.
127
Closes the table that is associated (on the handler tables hash) with the
128
name (table->alias) of the specified table.
135
bool mysql_ha_close(Session *session, TableList *tables)
137
TableList *hash_tables;
139
if ((hash_tables= (TableList*) hash_search(&session->handler_tables_hash,
140
(unsigned char*) tables->alias,
141
strlen(tables->alias) + 1)))
143
mysql_ha_close_table(session, hash_tables, false);
144
hash_delete(&session->handler_tables_hash, (unsigned char*) hash_tables);
148
my_error(ER_UNKNOWN_TABLE, MYF(0), tables->alias, "HANDLER");
158
Scan the handler tables hash for matching tables.
160
@param session Thread identifier.
161
@param tables The list of tables to remove.
163
@return Pointer to head of linked list (TableList::next_local) of matching
164
TableList elements from handler_tables_hash. Otherwise, NULL if no
168
static TableList *mysql_ha_find(Session *session, TableList *tables)
170
TableList *hash_tables, *head= NULL, *first= tables;
172
/* search for all handlers with matching table names */
173
for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
175
hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
176
for (tables= first; tables; tables= tables->next_local)
178
if ((! *tables->db ||
179
! my_strcasecmp(&my_charset_utf8_general_ci, hash_tables->db, tables->db)) &&
180
! my_strcasecmp(&my_charset_utf8_general_ci, hash_tables->table_name,
186
hash_tables->next_local= head;
196
Remove matching tables from the HANDLER's hash table.
198
@param session Thread identifier.
199
@param tables The list of tables to remove.
200
@param is_locked If LOCK_open is locked.
202
@note Broadcasts refresh if it closed a table with old version.
205
void mysql_ha_rm_tables(Session *session, TableList *tables, bool is_locked)
207
TableList *hash_tables, *next;
211
hash_tables= mysql_ha_find(session, tables);
215
next= hash_tables->next_local;
216
if (hash_tables->table)
217
mysql_ha_close_table(session, hash_tables, is_locked);
218
hash_delete(&session->handler_tables_hash, (unsigned char*) hash_tables);
227
Flush (close and mark for re-open) all tables that should be should
230
@param session Thread identifier.
232
@note Broadcasts refresh if it closed a table with old version.
235
void mysql_ha_flush(Session *session)
237
TableList *hash_tables;
239
safe_mutex_assert_owner(&LOCK_open);
241
for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
243
hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
244
if (hash_tables->table && hash_tables->table->needs_reopen_or_name_lock())
246
mysql_ha_close_table(session, hash_tables, true);
247
/* Mark table as closed, ready for re-open. */
248
hash_tables->table= NULL;
257
Close all HANDLER's tables.
259
@param session Thread identifier.
261
@note Broadcasts refresh if it closed a table with old version.
264
void mysql_ha_cleanup(Session *session)
266
TableList *hash_tables;
268
for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
270
hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
271
if (hash_tables->table)
272
mysql_ha_close_table(session, hash_tables, false);
275
hash_free(&session->handler_tables_hash);