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