~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_handler.cc

  • Committer: Monty Taylor
  • Date: 2008-08-04 19:37:18 UTC
  • mto: (261.2.2 codestyle)
  • mto: This revision was merged to the branch mainline in revision 262.
  • Revision ID: monty@inaugust.com-20080804193718-f0rz13uli4429ozb
Changed gettext_noop() to N_()

Show diffs side-by-side

added added

removed removed

Lines of Context:
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.
5
 
 
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.
10
 
 
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 */
14
 
 
15
 
 
16
 
/* HANDLER ... commands - direct access to ISAM */
17
 
 
18
 
/* TODO:
19
 
  HANDLER blabla OPEN [ AS foobar ] [ (column-list) ]
20
 
 
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.
24
 
 
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; }
30
 
 
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...
33
 
*/
34
 
 
35
 
/*
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.
57
 
*/
58
 
 
59
 
#include <drizzled/server_includes.h>
60
 
#include <drizzled/sql_select.h>
61
 
#include <drizzled/error.h>
62
 
#include <drizzled/sql_base.h>
63
 
 
64
 
 
65
 
/**
66
 
  Close a HANDLER table.
67
 
 
68
 
  @param session Thread identifier.
69
 
  @param tables A list of tables with the first entry to close.
70
 
  @param is_locked If LOCK_open is locked.
71
 
 
72
 
  @note Though this function takes a list of tables, only the first list entry
73
 
  will be closed.
74
 
  @note Broadcasts refresh if it closed a table with old version.
75
 
*/
76
 
 
77
 
static void mysql_ha_close_table(Session *session, TableList *tables,
78
 
                                 bool is_locked)
79
 
{
80
 
  Table **table_ptr;
81
 
 
82
 
  /*
83
 
    Though we could take the table pointer from hash_tables->table,
84
 
    we must follow the session->handler_tables chain anyway, as we need the
85
 
    address of the 'next' pointer referencing this table
86
 
    for close_thread_table().
87
 
  */
88
 
  for (table_ptr= &(session->handler_tables);
89
 
       *table_ptr && (*table_ptr != tables->table);
90
 
         table_ptr= &(*table_ptr)->next)
91
 
    ;
92
 
 
93
 
  if (*table_ptr)
94
 
  {
95
 
    (*table_ptr)->file->ha_index_or_rnd_end();
96
 
    if (! is_locked)
97
 
      pthread_mutex_lock(&LOCK_open);
98
 
    if (close_thread_table(session, table_ptr))
99
 
    {
100
 
      /* Tell threads waiting for refresh that something has happened */
101
 
      broadcast_refresh();
102
 
    }
103
 
    if (! is_locked)
104
 
      pthread_mutex_unlock(&LOCK_open);
105
 
  }
106
 
  else if (tables->table)
107
 
  {
108
 
    /* Must be a temporary table */
109
 
    Table *table= tables->table;
110
 
    table->file->ha_index_or_rnd_end();
111
 
    table->query_id= session->query_id;
112
 
    table->open_by_handler= 0;
113
 
  }
114
 
}
115
 
 
116
 
 
117
 
/*
118
 
  Close a HANDLER table by alias or table name
119
 
 
120
 
  SYNOPSIS
121
 
    mysql_ha_close()
122
 
    session                         Thread identifier.
123
 
    tables                      A list of tables with the first entry to close.
124
 
 
125
 
  DESCRIPTION
126
 
    Closes the table that is associated (on the handler tables hash) with the
127
 
    name (table->alias) of the specified table.
128
 
 
129
 
  RETURN
130
 
    false ok
131
 
    true  error
132
 
*/
133
 
 
134
 
bool mysql_ha_close(Session *session, TableList *tables)
135
 
{
136
 
  TableList    *hash_tables;
137
 
 
138
 
  if ((hash_tables= (TableList*) hash_search(&session->handler_tables_hash,
139
 
                                              (unsigned char*) tables->alias,
140
 
                                              strlen(tables->alias) + 1)))
141
 
  {
142
 
    mysql_ha_close_table(session, hash_tables, false);
143
 
    hash_delete(&session->handler_tables_hash, (unsigned char*) hash_tables);
144
 
  }
145
 
  else
146
 
  {
147
 
    my_error(ER_UNKNOWN_TABLE, MYF(0), tables->alias, "HANDLER");
148
 
    return(true);
149
 
  }
150
 
 
151
 
  my_ok(session);
152
 
  return(false);
153
 
}
154
 
 
155
 
 
156
 
/**
157
 
  Scan the handler tables hash for matching tables.
158
 
 
159
 
  @param session Thread identifier.
160
 
  @param tables The list of tables to remove.
161
 
 
162
 
  @return Pointer to head of linked list (TableList::next_local) of matching
163
 
          TableList elements from handler_tables_hash. Otherwise, NULL if no
164
 
          table was matched.
165
 
*/
166
 
 
167
 
static TableList *mysql_ha_find(Session *session, TableList *tables)
168
 
{
169
 
  TableList *hash_tables, *head= NULL, *first= tables;
170
 
 
171
 
  /* search for all handlers with matching table names */
172
 
  for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
173
 
  {
174
 
    hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
175
 
    for (tables= first; tables; tables= tables->next_local)
176
 
    {
177
 
      if ((! *tables->db ||
178
 
          ! my_strcasecmp(&my_charset_utf8_general_ci, hash_tables->db, tables->db)) &&
179
 
          ! my_strcasecmp(&my_charset_utf8_general_ci, hash_tables->table_name,
180
 
                          tables->table_name))
181
 
        break;
182
 
    }
183
 
    if (tables)
184
 
    {
185
 
      hash_tables->next_local= head;
186
 
      head= hash_tables;
187
 
    }
188
 
  }
189
 
 
190
 
  return(head);
191
 
}
192
 
 
193
 
 
194
 
/**
195
 
  Remove matching tables from the HANDLER's hash table.
196
 
 
197
 
  @param session Thread identifier.
198
 
  @param tables The list of tables to remove.
199
 
  @param is_locked If LOCK_open is locked.
200
 
 
201
 
  @note Broadcasts refresh if it closed a table with old version.
202
 
*/
203
 
 
204
 
void mysql_ha_rm_tables(Session *session, TableList *tables, bool is_locked)
205
 
{
206
 
  TableList *hash_tables, *next;
207
 
 
208
 
  assert(tables);
209
 
 
210
 
  hash_tables= mysql_ha_find(session, tables);
211
 
 
212
 
  while (hash_tables)
213
 
  {
214
 
    next= hash_tables->next_local;
215
 
    if (hash_tables->table)
216
 
      mysql_ha_close_table(session, hash_tables, is_locked);
217
 
    hash_delete(&session->handler_tables_hash, (unsigned char*) hash_tables);
218
 
    hash_tables= next;
219
 
  }
220
 
 
221
 
  return;
222
 
}
223
 
 
224
 
 
225
 
/**
226
 
  Flush (close and mark for re-open) all tables that should be should
227
 
  be reopen.
228
 
 
229
 
  @param session Thread identifier.
230
 
 
231
 
  @note Broadcasts refresh if it closed a table with old version.
232
 
*/
233
 
 
234
 
void mysql_ha_flush(Session *session)
235
 
{
236
 
  TableList *hash_tables;
237
 
 
238
 
  safe_mutex_assert_owner(&LOCK_open);
239
 
 
240
 
  for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
241
 
  {
242
 
    hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
243
 
    if (hash_tables->table && hash_tables->table->needs_reopen_or_name_lock())
244
 
    {
245
 
      mysql_ha_close_table(session, hash_tables, true);
246
 
      /* Mark table as closed, ready for re-open. */
247
 
      hash_tables->table= NULL;
248
 
    }
249
 
  }
250
 
 
251
 
  return;
252
 
}
253
 
 
254
 
 
255
 
/**
256
 
  Close all HANDLER's tables.
257
 
 
258
 
  @param session Thread identifier.
259
 
 
260
 
  @note Broadcasts refresh if it closed a table with old version.
261
 
*/
262
 
 
263
 
void mysql_ha_cleanup(Session *session)
264
 
{
265
 
  TableList *hash_tables;
266
 
 
267
 
  for (uint32_t i= 0; i < session->handler_tables_hash.records; i++)
268
 
  {
269
 
    hash_tables= (TableList*) hash_element(&session->handler_tables_hash, i);
270
 
    if (hash_tables->table)
271
 
      mysql_ha_close_table(session, hash_tables, false);
272
 
   }
273
 
 
274
 
  hash_free(&session->handler_tables_hash);
275
 
 
276
 
  return;
277
 
}