~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to drizzled/sql_rename.cc

pandora-build v0.100 - Fixes several bugs found by cb1kenobi. Add several thoughts from folks at LCA.

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/drizzled_error_messages.h>
21
 
 
22
 
static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list,
23
 
                                 bool skip_error);
24
 
 
25
 
static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list);
26
 
 
27
 
/*
28
 
  Every second entry in the table_list is the original name and every
29
 
  second entry is the new name.
30
 
*/
31
 
 
32
 
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list, bool silent)
33
 
{
34
 
  bool error= 1;
35
 
  TABLE_LIST *ren_table= 0;
36
 
 
37
 
  /*
38
 
    Avoid problems with a rename on a table that we have locked or
39
 
    if the user is trying to to do this in a transcation context
40
 
  */
41
 
  if (thd->locked_tables || thd->active_transaction())
42
 
  {
43
 
    my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
44
 
               ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
45
 
    return(1);
46
 
  }
47
 
 
48
 
  mysql_ha_rm_tables(thd, table_list, false);
49
 
 
50
 
  if (wait_if_global_read_lock(thd,0,1))
51
 
    return(1);
52
 
 
53
 
  pthread_mutex_lock(&LOCK_open);
54
 
  if (lock_table_names_exclusively(thd, table_list))
55
 
  {
56
 
    pthread_mutex_unlock(&LOCK_open);
57
 
    goto err;
58
 
  }
59
 
 
60
 
  error=0;
61
 
  if ((ren_table=rename_tables(thd,table_list,0)))
62
 
  {
63
 
    /* Rename didn't succeed;  rename back the tables in reverse order */
64
 
    TABLE_LIST *table;
65
 
 
66
 
    /* Reverse the table list */
67
 
    table_list= reverse_table_list(table_list);
68
 
 
69
 
    /* Find the last renamed table */
70
 
    for (table= table_list;
71
 
         table->next_local != ren_table ;
72
 
         table= table->next_local->next_local) ;
73
 
    table= table->next_local->next_local;               // Skip error table
74
 
    /* Revert to old names */
75
 
    rename_tables(thd, table, 1);
76
 
 
77
 
    /* Revert the table list (for prepared statements) */
78
 
    table_list= reverse_table_list(table_list);
79
 
 
80
 
    error= 1;
81
 
  }
82
 
  /*
83
 
    An exclusive lock on table names is satisfactory to ensure
84
 
    no other thread accesses this table.
85
 
    We still should unlock LOCK_open as early as possible, to provide
86
 
    higher concurrency - query_cache_invalidate can take minutes to
87
 
    complete.
88
 
  */
89
 
  pthread_mutex_unlock(&LOCK_open);
90
 
 
91
 
  /* Lets hope this doesn't fail as the result will be messy */ 
92
 
  if (!silent && !error)
93
 
  {
94
 
    write_bin_log(thd, true, thd->query, thd->query_length);
95
 
    my_ok(thd);
96
 
  }
97
 
 
98
 
  pthread_mutex_lock(&LOCK_open);
99
 
  unlock_table_names(thd, table_list, (TABLE_LIST*) 0);
100
 
  pthread_mutex_unlock(&LOCK_open);
101
 
 
102
 
err:
103
 
  start_waiting_global_read_lock(thd);
104
 
  return(error);
105
 
}
106
 
 
107
 
 
108
 
/*
109
 
  reverse table list
110
 
 
111
 
  SYNOPSIS
112
 
    reverse_table_list()
113
 
    table_list pointer to table _list
114
 
 
115
 
  RETURN
116
 
    pointer to new (reversed) list
117
 
*/
118
 
static TABLE_LIST *reverse_table_list(TABLE_LIST *table_list)
119
 
{
120
 
  TABLE_LIST *prev= 0;
121
 
 
122
 
  while (table_list)
123
 
  {
124
 
    TABLE_LIST *next= table_list->next_local;
125
 
    table_list->next_local= prev;
126
 
    prev= table_list;
127
 
    table_list= next;
128
 
  }
129
 
  return (prev);
130
 
}
131
 
 
132
 
 
133
 
/*
134
 
  Rename a single table or a view
135
 
 
136
 
  SYNPOSIS
137
 
    do_rename()
138
 
      thd               Thread handle
139
 
      ren_table         A table/view to be renamed
140
 
      new_db            The database to which the table to be moved to
141
 
      new_table_name    The new table/view name
142
 
      new_table_alias   The new table/view alias
143
 
      skip_error        Whether to skip error
144
 
 
145
 
  DESCRIPTION
146
 
    Rename a single table or a view.
147
 
 
148
 
  RETURN
149
 
    false     Ok
150
 
    true      rename failed
151
 
*/
152
 
 
153
 
bool
154
 
do_rename(THD *thd, TABLE_LIST *ren_table, char *new_db, char *new_table_name,
155
 
          char *new_table_alias, bool skip_error)
156
 
{
157
 
  int rc= 1;
158
 
  char name[FN_REFLEN];
159
 
  const char *new_alias, *old_alias;
160
 
  /* TODO: What should this really be set to - it doesn't
161
 
     get set anywhere before it's used? */
162
 
  enum legacy_db_type table_type=DB_TYPE_UNKNOWN;
163
 
 
164
 
  if (lower_case_table_names == 2)
165
 
  {
166
 
    old_alias= ren_table->alias;
167
 
    new_alias= new_table_alias;
168
 
  }
169
 
  else
170
 
  {
171
 
    old_alias= ren_table->table_name;
172
 
    new_alias= new_table_name;
173
 
  }
174
 
  build_table_filename(name, sizeof(name),
175
 
                       new_db, new_alias, reg_ext, 0);
176
 
  if (!access(name,F_OK))
177
 
  {
178
 
    my_error(ER_TABLE_EXISTS_ERROR, MYF(0), new_alias);
179
 
    return(1);                  // This can't be skipped
180
 
  }
181
 
  build_table_filename(name, sizeof(name),
182
 
                       ren_table->db, old_alias, reg_ext, 0);
183
 
 
184
 
  rc= mysql_rename_table(ha_resolve_by_legacy_type(thd, table_type),
185
 
                               ren_table->db, old_alias,
186
 
                               new_db, new_alias, 0);
187
 
  if (rc && !skip_error)
188
 
    return(1);
189
 
 
190
 
  return(0);
191
 
 
192
 
}
193
 
/*
194
 
  Rename all tables in list; Return pointer to wrong entry if something goes
195
 
  wrong.  Note that the table_list may be empty!
196
 
*/
197
 
 
198
 
/*
199
 
  Rename tables/views in the list
200
 
 
201
 
  SYNPOSIS
202
 
    rename_tables()
203
 
      thd               Thread handle
204
 
      table_list        List of tables to rename
205
 
      skip_error        Whether to skip errors
206
 
 
207
 
  DESCRIPTION
208
 
    Take a table/view name from and odd list element and rename it to a
209
 
    the name taken from list element+1. Note that the table_list may be
210
 
    empty.
211
 
 
212
 
  RETURN
213
 
    false     Ok
214
 
    true      rename failed
215
 
*/
216
 
 
217
 
static TABLE_LIST *
218
 
rename_tables(THD *thd, TABLE_LIST *table_list, bool skip_error)
219
 
{
220
 
  TABLE_LIST *ren_table, *new_table;
221
 
 
222
 
  for (ren_table= table_list; ren_table; ren_table= new_table->next_local)
223
 
  {
224
 
    new_table= ren_table->next_local;
225
 
    if (do_rename(thd, ren_table, new_table->db, new_table->table_name,
226
 
                  new_table->alias, skip_error))
227
 
      return(ren_table);
228
 
  }
229
 
  return(0);
230
 
}