Drizzled Public API Documentation

schema_engine.cc

00001 /* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
00002  *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
00003  *
00004  *  Copyright (C) 2010 Brian Aker
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; version 2 of the License.
00009  *
00010  *  This program is distributed in the hope that it will be useful,
00011  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  *  GNU General Public License for more details.
00014  *
00015  *  You should have received a copy of the GNU General Public License
00016  *  along with this program; if not, write to the Free Software
00017  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00018  */
00019 
00020 #include <config.h>
00021 
00022 #include <drizzled/session.h>
00023 #include <drizzled/sql_base.h>
00024 #include <drizzled/global_charset_info.h>
00025 #include <drizzled/charset.h>
00026 #include <drizzled/transaction_services.h>
00027 
00028 #include <drizzled/plugin/storage_engine.h>
00029 #include <drizzled/plugin/authorization.h>
00030 
00031 namespace drizzled
00032 {
00033 
00034 namespace plugin
00035 {
00036 
00037 class AddSchemaNames :
00038   public std::unary_function<StorageEngine *, void>
00039 {
00040   identifier::Schema::vector &schemas;
00041 
00042 public:
00043 
00044   AddSchemaNames(identifier::Schema::vector &of_names) :
00045     schemas(of_names)
00046   {
00047   }
00048 
00049   result_type operator() (argument_type engine)
00050   {
00051     engine->doGetSchemaIdentifiers(schemas);
00052   }
00053 };
00054 
00055 void StorageEngine::getIdentifiers(Session &session, identifier::Schema::vector &schemas)
00056 {
00057   // Add hook here for engines to register schema.
00058   std::for_each(StorageEngine::getSchemaEngines().begin(), StorageEngine::getSchemaEngines().end(),
00059            AddSchemaNames(schemas));
00060 
00061   plugin::Authorization::pruneSchemaNames(*session.user(), schemas);
00062 }
00063 
00064 class StorageEngineGetSchemaDefinition: public std::unary_function<StorageEngine *, bool>
00065 {
00066   const identifier::Schema &identifier;
00067   message::schema::shared_ptr &schema_proto;
00068 
00069 public:
00070   StorageEngineGetSchemaDefinition(const identifier::Schema &identifier_arg,
00071                                    message::schema::shared_ptr &schema_proto_arg) :
00072     identifier(identifier_arg),
00073     schema_proto(schema_proto_arg)
00074   {
00075   }
00076 
00077   result_type operator() (argument_type engine)
00078   {
00079     schema_proto= engine->doGetSchemaDefinition(identifier);
00080     return schema_proto;
00081   }
00082 };
00083 
00084 /*
00085   Return value is "if parsed"
00086 */
00087 message::schema::shared_ptr StorageEngine::getSchemaDefinition(const drizzled::identifier::Table &identifier)
00088 {
00089   identifier::Schema schema_identifier= identifier;
00090   return StorageEngine::getSchemaDefinition(schema_identifier);
00091 }
00092 
00093 message::schema::shared_ptr StorageEngine::getSchemaDefinition(const identifier::Schema &identifier)
00094 {
00095   message::schema::shared_ptr proto;
00096 
00097   EngineVector::iterator iter=
00098     std::find_if(StorageEngine::getSchemaEngines().begin(), StorageEngine::getSchemaEngines().end(),
00099                  StorageEngineGetSchemaDefinition(identifier, proto));
00100 
00101   if (iter != StorageEngine::getSchemaEngines().end())
00102   {
00103     return proto;
00104   }
00105 
00106   return message::schema::shared_ptr();
00107 }
00108 
00109 bool StorageEngine::doesSchemaExist(const identifier::Schema &identifier)
00110 {
00111   message::schema::shared_ptr proto;
00112 
00113   return StorageEngine::getSchemaDefinition(identifier);
00114 }
00115 
00116 
00117 const CHARSET_INFO *StorageEngine::getSchemaCollation(const identifier::Schema &identifier)
00118 {
00119   message::schema::shared_ptr schmema_proto;
00120 
00121   schmema_proto= StorageEngine::getSchemaDefinition(identifier);
00122 
00123   if (schmema_proto && schmema_proto->has_collation())
00124   {
00125     const std::string buffer= schmema_proto->collation();
00126     const CHARSET_INFO* cs= get_charset_by_name(buffer.c_str());
00127 
00128     if (not cs)
00129     {
00130       std::string path;
00131       identifier.getSQLPath(path);
00132 
00133       errmsg_printf(error::ERROR,
00134                     _("Error while loading database options: '%s':"), path.c_str());
00135       errmsg_printf(error::ERROR, ER(ER_UNKNOWN_COLLATION), buffer.c_str());
00136 
00137       return default_charset_info;
00138     }
00139 
00140     return cs;
00141   }
00142 
00143   return default_charset_info;
00144 }
00145 
00146 class CreateSchema :
00147   public std::unary_function<StorageEngine *, void>
00148 {
00149   const drizzled::message::Schema &schema_message;
00150   uint64_t &success_count;
00151 
00152 public:
00153 
00154   CreateSchema(const drizzled::message::Schema &arg, uint64_t &success_count_arg) :
00155     schema_message(arg),
00156     success_count(success_count_arg)
00157   {
00158   }
00159 
00160   result_type operator() (argument_type engine)
00161   {
00162     // @todo eomeday check that at least one engine said "true"
00163     bool success= engine->doCreateSchema(schema_message);
00164 
00165     if (success)
00166     {
00167       success_count++;
00168       TransactionServices &transaction_services= TransactionServices::singleton();
00169       transaction_services.allocateNewTransactionId();
00170     }
00171   }
00172 };
00173 
00174 bool StorageEngine::createSchema(const drizzled::message::Schema &schema_message)
00175 {
00176   // Add hook here for engines to register schema.
00177   uint64_t success_count= 0;
00178   std::for_each(StorageEngine::getSchemaEngines().begin(), StorageEngine::getSchemaEngines().end(),
00179                 CreateSchema(schema_message, success_count));
00180 
00181   if (success_count)
00182   {
00183     TransactionServices &transaction_services= TransactionServices::singleton();
00184     transaction_services.allocateNewTransactionId();
00185   }
00186 
00187   return (bool)success_count;
00188 }
00189 
00190 class DropSchema :
00191   public std::unary_function<StorageEngine *, void>
00192 {
00193   uint64_t &success_count;
00194   const identifier::Schema &identifier;
00195 
00196 public:
00197 
00198   DropSchema(const identifier::Schema &arg, uint64_t &count_arg) :
00199     success_count(count_arg),
00200     identifier(arg)
00201   {
00202   }
00203 
00204   result_type operator() (argument_type engine)
00205   {
00206     // @todo someday check that at least one engine said "true"
00207     bool success= engine->doDropSchema(identifier);
00208 
00209     if (success)
00210     {
00211       success_count++;
00212       TransactionServices &transaction_services= TransactionServices::singleton();
00213       transaction_services.allocateNewTransactionId();
00214     }
00215   }
00216 };
00217 
00218 static bool drop_all_tables_in_schema(Session& session,
00219                                       identifier::Schema::const_reference identifier,
00220                                       identifier::Table::vector &dropped_tables,
00221                                       uint64_t &deleted)
00222 {
00223   TransactionServices &transaction_services= TransactionServices::singleton();
00224 
00225   plugin::StorageEngine::getIdentifiers(session, identifier, dropped_tables);
00226 
00227   for (identifier::Table::vector::iterator it= dropped_tables.begin();
00228        it != dropped_tables.end();
00229        it++)
00230   {
00231     boost::mutex::scoped_lock scopedLock(table::Cache::singleton().mutex());
00232 
00233     message::table::shared_ptr message= StorageEngine::getTableMessage(session, *it, false);
00234     if (not message)
00235     {
00236       my_error(ER_TABLE_DROP, *it);
00237       return false;
00238     }
00239 
00240     table::Cache::singleton().removeTable(&session, *it,
00241                                           RTFC_WAIT_OTHER_THREAD_FLAG |
00242                                           RTFC_CHECK_KILLED_FLAG);
00243     if (not plugin::StorageEngine::dropTable(session, *it))
00244     {
00245       my_error(ER_TABLE_DROP, *it);
00246       return false;
00247     }
00248     transaction_services.dropTable(session, *it, *message, true);
00249     deleted++;
00250   }
00251 
00252   return true;
00253 }
00254 
00255 bool StorageEngine::dropSchema(Session::reference session,
00256                                identifier::Schema::const_reference identifier,
00257                                message::schema::const_reference schema_message)
00258 {
00259   uint64_t deleted= 0;
00260   bool error= false;
00261   identifier::Table::vector dropped_tables;
00262 
00263   do
00264   {
00265     // Remove all temp tables first, this prevents loss of table from
00266     // shadowing (ie temp over standard table)
00267     {
00268       // Lets delete the temporary tables first outside of locks.
00269       identifier::Table::vector set_of_identifiers;
00270       session.doGetTableIdentifiers(identifier, set_of_identifiers);
00271 
00272       for (identifier::Table::vector::iterator iter= set_of_identifiers.begin(); iter != set_of_identifiers.end(); iter++)
00273       {
00274         if (session.drop_temporary_table(*iter))
00275         {
00276           my_error(ER_TABLE_DROP, *iter);
00277           error= true;
00278           break;
00279         }
00280       }
00281     }
00282 
00283     /* After deleting database, remove all cache entries related to schema */
00284     table::Cache::singleton().removeSchema(identifier);
00285 
00286     if (not drop_all_tables_in_schema(session, identifier, dropped_tables, deleted))
00287     {
00288       error= true;
00289       my_error(ER_DROP_SCHEMA, identifier);
00290       break;
00291     }
00292 
00293     uint64_t counter= 0;
00294     // Add hook here for engines to register schema.
00295     std::for_each(StorageEngine::getSchemaEngines().begin(), StorageEngine::getSchemaEngines().end(),
00296                   DropSchema(identifier, counter));
00297 
00298     if (not counter)
00299     {
00300       my_error(ER_DROP_SCHEMA, identifier);
00301       error= true;
00302 
00303       break;
00304     }
00305     else
00306     {
00307       /* We've already verified that the schema does exist, so safe to log it */
00308       TransactionServices &transaction_services= TransactionServices::singleton();
00309       transaction_services.dropSchema(session, identifier, schema_message);
00310     }
00311   } while (0);
00312 
00313   if (deleted > 0)
00314   {
00315     session.clear_error();
00316     session.server_status|= SERVER_STATUS_DB_DROPPED;
00317     session.my_ok((uint32_t) deleted);
00318     session.server_status&= ~SERVER_STATUS_DB_DROPPED;
00319   }
00320 
00321 
00322   return error;
00323 }
00324 
00325 class AlterSchema :
00326   public std::unary_function<StorageEngine *, void>
00327 {
00328   uint64_t &success_count;
00329   const drizzled::message::Schema &schema_message;
00330 
00331 public:
00332 
00333   AlterSchema(const drizzled::message::Schema &arg, uint64_t &count_arg) :
00334     success_count(count_arg),
00335     schema_message(arg)
00336   {
00337   }
00338 
00339   result_type operator() (argument_type engine)
00340   {
00341     // @todo eomeday check that at least one engine said "true"
00342     bool success= engine->doAlterSchema(schema_message);
00343 
00344 
00345     if (success)
00346     {
00347       success_count++;
00348     }
00349   }
00350 };
00351 
00352 bool StorageEngine::alterSchema(const drizzled::message::Schema &schema_message)
00353 {
00354   uint64_t success_count= 0;
00355 
00356   std::for_each(StorageEngine::getSchemaEngines().begin(), StorageEngine::getSchemaEngines().end(),
00357                 AlterSchema(schema_message, success_count));
00358 
00359   if (success_count)
00360   {
00361     TransactionServices &transaction_services= TransactionServices::singleton();
00362     transaction_services.allocateNewTransactionId();
00363   }
00364 
00365   return success_count ? true : false;
00366 }
00367 
00368 } /* namespace plugin */
00369 } /* namespace drizzled */