Drizzled Public API Documentation

rename_table.cc
00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2009 Sun Microsystems, Inc.
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00019  */
00020 
00021 #include <config.h>
00022 #include <drizzled/show.h>
00023 #include <drizzled/lock.h>
00024 #include <drizzled/session.h>
00025 #include <drizzled/statement/rename_table.h>
00026 #include <drizzled/pthread_globals.h>
00027 #include <drizzled/plugin/storage_engine.h>
00028 #include <drizzled/transaction_services.h>
00029 #include <drizzled/sql_lex.h>
00030 #include <drizzled/table/cache.h>
00031 
00032 namespace drizzled {
00033 
00034 bool statement::RenameTable::execute()
00035 {
00036   TableList *first_table= (TableList *) lex().select_lex.table_list.first;
00037   TableList *all_tables= lex().query_tables;
00038   assert(first_table == all_tables && first_table != 0);
00039   TableList *table;
00040 
00041   if (session().inTransaction())
00042   {
00043     my_error(ER_TRANSACTIONAL_DDL_NOT_SUPPORTED, MYF(0));
00044     return true;
00045   }
00046 
00047   for (table= first_table; table; table= table->next_local->next_local)
00048   {
00049     TableList old_list, new_list;
00050     /*
00051        we do not need initialize old_list and new_list because we will
00052        come table[0] and table->next[0] there
00053      */
00054     old_list= table[0];
00055     new_list= table->next_local[0];
00056   }
00057 
00058   if (renameTables(first_table))
00059   {
00060     return true;
00061   }
00062 
00063   return false;
00064 }
00065 
00066 bool statement::RenameTable::renameTables(TableList *table_list)
00067 {
00068   bool error= true;
00069   TableList *ren_table= NULL;
00070 
00071   /*
00072     Avoid problems with a rename on a table that we have locked or
00073     if the user is trying to to do this in a transcation context
00074   */
00075   if (session().inTransaction())
00076   {
00077     my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
00078     return true;
00079   }
00080 
00081   if (session().wait_if_global_read_lock(false, true))
00082     return true;
00083 
00084   {
00085     boost::mutex::scoped_lock scopedLock(table::Cache::mutex()); /* Rename table lock for exclusive access */
00086 
00087     if (not session().lock_table_names_exclusively(table_list))
00088     {
00089       error= false;
00090       ren_table= renameTablesInList(table_list, false);
00091 
00092       if (ren_table)
00093       {
00094         /* Rename didn't succeed;  rename back the tables in reverse order */
00095         TableList *table;
00096 
00097         /* Reverse the table list */
00098         table_list= reverseTableList(table_list);
00099 
00100         /* Find the last renamed table */
00101         for (table= table_list;
00102              table->next_local != ren_table;
00103              table= table->next_local->next_local) 
00104         { /* do nothing */ }
00105 
00106         table= table->next_local->next_local;   // Skip error table
00107 
00108         /* Revert to old names */
00109         renameTablesInList(table, true);
00110         error= true;
00111       }
00112 
00113       table_list->unlock_table_names();
00114     }
00115   }
00116 
00117   /* Lets hope this doesn't fail as the result will be messy */
00118   if (not error)
00119   {
00120     TransactionServices::rawStatement(session(), *session().getQueryString(), *session().schema());        
00121     session().my_ok();
00122   }
00123 
00124   session().startWaitingGlobalReadLock();
00125 
00126   return error;
00127 }
00128 
00129 TableList *statement::RenameTable::reverseTableList(TableList *table_list)
00130 {
00131   TableList *prev= NULL;
00132 
00133   while (table_list)
00134   {
00135     TableList *next= table_list->next_local;
00136     table_list->next_local= prev;
00137     prev= table_list;
00138     table_list= next;
00139   }
00140   return prev;
00141 }
00142 
00143 bool statement::RenameTable::rename(TableList *ren_table,
00144                                     const char *new_db,
00145                                     const char *new_table_name,
00146                                     bool skip_error)
00147 {
00148   bool rc= true;
00149   const char *new_alias, *old_alias;
00150 
00151   {
00152     old_alias= ren_table->getTableName();
00153     new_alias= new_table_name;
00154   }
00155 
00156   plugin::StorageEngine *engine= NULL;
00157   message::table::shared_ptr table_message;
00158 
00159   identifier::Table old_identifier(ren_table->getSchemaName(), old_alias, message::Table::STANDARD);
00160 
00161   if (not (table_message= plugin::StorageEngine::getTableMessage(session(), old_identifier)))
00162   {
00163     my_error(ER_TABLE_UNKNOWN, old_identifier);
00164     return true;
00165   }
00166 
00167   engine= plugin::StorageEngine::findByName(session(), table_message->engine().name());
00168 
00169   identifier::Table new_identifier(new_db, new_alias, message::Table::STANDARD);
00170   if (plugin::StorageEngine::doesTableExist(session(), new_identifier))
00171   {
00172     my_error(ER_TABLE_EXISTS_ERROR, new_identifier);
00173     return 1; // This can't be skipped
00174   }
00175 
00176   rc= rename_table(session(), engine, old_identifier, new_identifier);
00177   if (rc && ! skip_error)
00178     return true;
00179 
00180   return false;
00181 }
00182 
00183 TableList *statement::RenameTable::renameTablesInList(TableList *table_list,
00184                                                       bool skip_error)
00185 {
00186   TableList *ren_table, *new_table;
00187 
00188   for (ren_table= table_list; ren_table; ren_table= new_table->next_local)
00189   {
00190     new_table= ren_table->next_local;
00191     if (rename(ren_table, new_table->getSchemaName(), new_table->getTableName(), skip_error))
00192       return ren_table;
00193   }
00194   return 0;
00195 }
00196 
00197 } /* namespace drizzled */