~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/rename.cc

Merge Padraig

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* Copyright (C) 2000-2006 MySQL AB
2
 
 
3
 
   This program is free software; you can redistribute it and/or modify
4
 
   it under the terms of the GNU General Public License as published by
5
 
   the Free Software Foundation; version 2 of the License.
6
 
 
7
 
   This program is distributed in the hope that it will be useful,
8
 
   but WITHOUT ANY WARRANTY; without even the implied warranty of
9
 
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10
 
   GNU General Public License for more details.
11
 
 
12
 
   You should have received a copy of the GNU General Public License
13
 
   along with this program; if not, write to the Free Software
14
 
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
15
 
 
16
 
/*
17
 
  Atomic rename of table;  RENAME TABLE t1 to t2, tmp to t1 [,...]
18
 
*/
19
 
#include <drizzled/server_includes.h>
20
 
#include <drizzled/error.h>
21
 
#include <drizzled/table_list.h>
22
 
#include <drizzled/session.h>
23
 
#include <drizzled/lock.h>
24
 
#include "drizzled/rename.h"
25
 
 
26
 
using namespace drizzled;
27
 
 
28
 
static TableList *rename_tables(Session *session, TableList *table_list,
29
 
                                bool skip_error);
30
 
 
31
 
static TableList *reverse_table_list(TableList *table_list);
32
 
 
33
 
/*
34
 
  Every second entry in the table_list is the original name and every
35
 
  second entry is the new name.
36
 
*/
37
 
bool drizzle_rename_tables(Session *session, TableList *table_list)
38
 
{
39
 
  bool error= true;
40
 
  TableList *ren_table= NULL;
41
 
 
42
 
  /*
43
 
    Avoid problems with a rename on a table that we have locked or
44
 
    if the user is trying to to do this in a transcation context
45
 
  */
46
 
  if (session->inTransaction())
47
 
  {
48
 
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
49
 
    return true;
50
 
  }
51
 
 
52
 
  if (wait_if_global_read_lock(session,0,1))
53
 
    return true;
54
 
 
55
 
  pthread_mutex_lock(&LOCK_open); /* Rename table lock for exclusive access */
56
 
  if (lock_table_names_exclusively(session, table_list))
57
 
  {
58
 
    pthread_mutex_unlock(&LOCK_open);
59
 
    goto err;
60
 
  }
61
 
 
62
 
  error= false;
63
 
  if ((ren_table=rename_tables(session,table_list,0)))
64
 
  {
65
 
    /* Rename didn't succeed;  rename back the tables in reverse order */
66
 
    TableList *table;
67
 
 
68
 
    /* Reverse the table list */
69
 
    table_list= reverse_table_list(table_list);
70
 
 
71
 
    /* Find the last renamed table */
72
 
    for (table= table_list;
73
 
         table->next_local != ren_table ;
74
 
         table= table->next_local->next_local) ;
75
 
    table= table->next_local->next_local;               // Skip error table
76
 
    /* Revert to old names */
77
 
    rename_tables(session, table, 1);
78
 
 
79
 
    /* Revert the table list (for prepared statements) */
80
 
    table_list= reverse_table_list(table_list);
81
 
 
82
 
    error= true;
83
 
  }
84
 
  /*
85
 
    An exclusive lock on table names is satisfactory to ensure
86
 
    no other thread accesses this table.
87
 
    We still should unlock LOCK_open as early as possible, to provide
88
 
    higher concurrency - query_cache_invalidate can take minutes to
89
 
    complete.
90
 
  */
91
 
  pthread_mutex_unlock(&LOCK_open);
92
 
 
93
 
  /* Lets hope this doesn't fail as the result will be messy */
94
 
  if (!error)
95
 
  {
96
 
    write_bin_log(session, true, session->query, session->query_length);
97
 
    session->my_ok();
98
 
  }
99
 
 
100
 
  pthread_mutex_lock(&LOCK_open); /* unlock all tables held */
101
 
  unlock_table_names(table_list, NULL);
102
 
  pthread_mutex_unlock(&LOCK_open);
103
 
 
104
 
err:
105
 
  start_waiting_global_read_lock(session);
106
 
 
107
 
  return error;
108
 
}
109
 
 
110
 
 
111
 
/*
112
 
  reverse table list
113
 
 
114
 
  SYNOPSIS
115
 
    reverse_table_list()
116
 
    table_list pointer to table _list
117
 
 
118
 
  RETURN
119
 
    pointer to new (reversed) list
120
 
*/
121
 
static TableList *reverse_table_list(TableList *table_list)
122
 
{
123
 
  TableList *prev= NULL;
124
 
 
125
 
  while (table_list)
126
 
  {
127
 
    TableList *next= table_list->next_local;
128
 
    table_list->next_local= prev;
129
 
    prev= table_list;
130
 
    table_list= next;
131
 
  }
132
 
  return (prev);
133
 
}
134
 
 
135
 
 
136
 
/*
137
 
  Rename a single table or a view
138
 
 
139
 
  SYNPOSIS
140
 
    do_rename()
141
 
      session               Thread handle
142
 
      ren_table         A table/view to be renamed
143
 
      new_db            The database to which the table to be moved to
144
 
      new_table_name    The new table/view name
145
 
      skip_error        Whether to skip error
146
 
 
147
 
  DESCRIPTION
148
 
    Rename a single table or a view.
149
 
 
150
 
  RETURN
151
 
    false     Ok
152
 
    true      rename failed
153
 
*/
154
 
 
155
 
static bool
156
 
do_rename(Session *session, TableList *ren_table, const char *new_db, const char *new_table_name, bool skip_error)
157
 
{
158
 
  bool rc= true;
159
 
  const char *new_alias, *old_alias;
160
 
 
161
 
  {
162
 
    old_alias= ren_table->table_name;
163
 
    new_alias= new_table_name;
164
 
  }
165
 
 
166
 
  StorageEngine *engine= NULL;
167
 
  message::Table table_proto;
168
 
  char path[FN_REFLEN];
169
 
  size_t length;
170
 
 
171
 
  length= build_table_filename(path, sizeof(path),
172
 
                               ren_table->db, old_alias, false);
173
 
 
174
 
  if (StorageEngine::getTableProto(path, &table_proto)!= EEXIST)
175
 
  {
176
 
    my_error(ER_NO_SUCH_TABLE, MYF(0), ren_table->db, old_alias);
177
 
    return true;
178
 
  }
179
 
 
180
 
  engine= ha_resolve_by_name(session, table_proto.engine().name());
181
 
 
182
 
  length= build_table_filename(path, sizeof(path),
183
 
                               new_db, new_alias, false);
184
 
 
185
 
  if (StorageEngine::getTableProto(path, NULL)!=ENOENT)
186
 
  {
187
 
    my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
188
 
    return(1);                  // This can't be skipped
189
 
  }
190
 
 
191
 
  rc= mysql_rename_table(engine,
192
 
                         ren_table->db, old_alias,
193
 
                         new_db, new_alias, 0);
194
 
  if (rc && !skip_error)
195
 
    return true;
196
 
 
197
 
  return false;
198
 
 
199
 
}
200
 
/*
201
 
  Rename all tables in list; Return pointer to wrong entry if something goes
202
 
  wrong.  Note that the table_list may be empty!
203
 
*/
204
 
 
205
 
/*
206
 
  Rename tables/views in the list
207
 
 
208
 
  SYNPOSIS
209
 
    rename_tables()
210
 
      session               Thread handle
211
 
      table_list        List of tables to rename
212
 
      skip_error        Whether to skip errors
213
 
 
214
 
  DESCRIPTION
215
 
    Take a table/view name from and odd list element and rename it to a
216
 
    the name taken from list element+1. Note that the table_list may be
217
 
    empty.
218
 
 
219
 
  RETURN
220
 
    false     Ok
221
 
    true      rename failed
222
 
*/
223
 
 
224
 
static TableList *
225
 
rename_tables(Session *session, TableList *table_list, bool skip_error)
226
 
{
227
 
  TableList *ren_table, *new_table;
228
 
 
229
 
  for (ren_table= table_list; ren_table; ren_table= new_table->next_local)
230
 
  {
231
 
    new_table= ren_table->next_local;
232
 
    if (do_rename(session, ren_table, new_table->db, new_table->table_name, skip_error))
233
 
      return(ren_table);
234
 
  }
235
 
  return(0);
236
 
}