21
21
the most natural (easiest, fastest) way to do it is to
22
22
compute List<Item> field_list not in mysql_ha_read
23
but in mysql_ha_open, and then store it in TABLE structure.
23
but in mysql_ha_open, and then store it in Table structure.
25
25
The problem here is that mysql_parse calls free_item to free all the
26
26
items allocated at the end of every query. The workaround would to
36
36
There are two containers holding information about open handler tables.
37
The first is 'thd->handler_tables'. It is a linked list of TABLE objects.
37
The first is 'thd->handler_tables'. It is a linked list of Table objects.
38
38
It is used like 'thd->open_tables' in the table cache. The trick is to
39
39
exchange these two lists during open and lock of tables. Thus the normal
40
40
table cache code can be used.
41
The second container is a HASH. It holds objects of the type TABLE_LIST.
41
The second container is a HASH. It holds objects of the type TableList.
42
42
Despite its name, no lists of tables but only single structs are hashed
43
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
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
46
blocked by handler tables still in use. Since we use the normal table cache
47
47
functions with 'thd->handler_tables', the closed tables are removed from
48
48
this list. Hence we need the original open information for the handler
49
49
table in the case that it is used again. This information is handed over
50
to mysql_ha_open() as a TABLE_LIST. So we store this information in the
51
second container, where it is not affected by FLUSH TABLE. The second
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
52
container is implemented as a hash for performance reasons. Consequently,
53
53
we use it not only for re-opening a handler table, but also for the
54
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
55
Table structure (in the first container) in the TBALE_LIST object in the
56
56
second container. When the table is flushed, the pointer is cleared.
59
#include "mysql_priv.h"
60
#include "sql_select.h"
59
#include <drizzled/server_includes.h>
60
#include <drizzled/sql_select.h>
63
62
#define HANDLER_TABLES_HASH_SIZE 120
74
73
@note Broadcasts refresh if it closed a table with old version.
77
static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
76
static void mysql_ha_close_table(THD *thd, TableList *tables,
83
82
Though we could take the table pointer from hash_tables->table,
95
94
(*table_ptr)->file->ha_index_or_rnd_end();
97
VOID(pthread_mutex_lock(&LOCK_open));
96
pthread_mutex_lock(&LOCK_open);
98
97
if (close_thread_table(thd, table_ptr))
100
99
/* Tell threads waiting for refresh that something has happened */
101
100
broadcast_refresh();
104
VOID(pthread_mutex_unlock(&LOCK_open));
103
pthread_mutex_unlock(&LOCK_open);
106
105
else if (tables->table)
108
107
/* Must be a temporary table */
109
TABLE *table= tables->table;
108
Table *table= tables->table;
110
109
table->file->ha_index_or_rnd_end();
111
110
table->query_id= thd->query_id;
112
111
table->open_by_handler= 0;
127
126
name (table->alias) of the specified table.
134
bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
133
bool mysql_ha_close(THD *thd, TableList *tables)
136
TABLE_LIST *hash_tables;
137
DBUG_ENTER("mysql_ha_close");
138
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
139
tables->db, tables->table_name, tables->alias));
135
TableList *hash_tables;
141
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
142
(uchar*) tables->alias,
137
if ((hash_tables= (TableList*) hash_search(&thd->handler_tables_hash,
138
(unsigned char*) tables->alias,
143
139
strlen(tables->alias) + 1)))
145
mysql_ha_close_table(thd, hash_tables, FALSE);
146
hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
141
mysql_ha_close_table(thd, hash_tables, false);
142
hash_delete(&thd->handler_tables_hash, (unsigned char*) hash_tables);
150
146
my_error(ER_UNKNOWN_TABLE, MYF(0), tables->alias, "HANDLER");
151
DBUG_PRINT("exit",("ERROR"));
156
DBUG_PRINT("exit", ("OK"));
164
158
@param thd Thread identifier.
165
159
@param tables The list of tables to remove.
167
@return Pointer to head of linked list (TABLE_LIST::next_local) of matching
168
TABLE_LIST elements from handler_tables_hash. Otherwise, NULL if no
161
@return Pointer to head of linked list (TableList::next_local) of matching
162
TableList elements from handler_tables_hash. Otherwise, NULL if no
169
163
table was matched.
172
static TABLE_LIST *mysql_ha_find(THD *thd, TABLE_LIST *tables)
166
static TableList *mysql_ha_find(THD *thd, TableList *tables)
174
TABLE_LIST *hash_tables, *head= NULL, *first= tables;
175
DBUG_ENTER("mysql_ha_find");
168
TableList *hash_tables, *head= NULL, *first= tables;
177
170
/* search for all handlers with matching table names */
178
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
171
for (uint32_t i= 0; i < thd->handler_tables_hash.records; i++)
180
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
173
hash_tables= (TableList*) hash_element(&thd->handler_tables_hash, i);
181
174
for (tables= first; tables; tables= tables->next_local)
183
176
if ((! *tables->db ||
184
! my_strcasecmp(&my_charset_latin1, hash_tables->db, tables->db)) &&
185
! my_strcasecmp(&my_charset_latin1, hash_tables->table_name,
177
! my_strcasecmp(&my_charset_utf8_general_ci, hash_tables->db, tables->db)) &&
178
! my_strcasecmp(&my_charset_utf8_general_ci, hash_tables->table_name,
186
179
tables->table_name))
207
200
@note Broadcasts refresh if it closed a table with old version.
210
void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked)
203
void mysql_ha_rm_tables(THD *thd, TableList *tables, bool is_locked)
212
TABLE_LIST *hash_tables, *next;
213
DBUG_ENTER("mysql_ha_rm_tables");
205
TableList *hash_tables, *next;
217
209
hash_tables= mysql_ha_find(thd, tables);
221
213
next= hash_tables->next_local;
222
214
if (hash_tables->table)
223
215
mysql_ha_close_table(thd, hash_tables, is_locked);
224
hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
216
hash_delete(&thd->handler_tables_hash, (unsigned char*) hash_tables);
225
217
hash_tables= next;
241
233
void mysql_ha_flush(THD *thd)
243
TABLE_LIST *hash_tables;
244
DBUG_ENTER("mysql_ha_flush");
235
TableList *hash_tables;
246
237
safe_mutex_assert_owner(&LOCK_open);
248
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
239
for (uint32_t i= 0; i < thd->handler_tables_hash.records; i++)
250
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
241
hash_tables= (TableList*) hash_element(&thd->handler_tables_hash, i);
251
242
if (hash_tables->table && hash_tables->table->needs_reopen_or_name_lock())
253
mysql_ha_close_table(thd, hash_tables, TRUE);
244
mysql_ha_close_table(thd, hash_tables, true);
254
245
/* Mark table as closed, ready for re-open. */
255
246
hash_tables->table= NULL;
271
262
void mysql_ha_cleanup(THD *thd)
273
TABLE_LIST *hash_tables;
274
DBUG_ENTER("mysql_ha_cleanup");
264
TableList *hash_tables;
276
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
266
for (uint32_t i= 0; i < thd->handler_tables_hash.records; i++)
278
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
268
hash_tables= (TableList*) hash_element(&thd->handler_tables_hash, i);
279
269
if (hash_tables->table)
280
mysql_ha_close_table(thd, hash_tables, FALSE);
270
mysql_ha_close_table(thd, hash_tables, false);
283
273
hash_free(&thd->handler_tables_hash);