~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_handler.cc

  • Committer: Jay Pipes
  • Date: 2009-05-31 21:21:44 UTC
  • mto: This revision was merged to the branch mainline in revision 1046.
  • Revision ID: jpipes@serialcoder-20090531212144-dn18058mx55azhms
Yet more indentation and style cleanup

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