Drizzled Public API Documentation

storage_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) 2008 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; 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 <fcntl.h>
00023 #include <unistd.h>
00024 
00025 #include <string>
00026 #include <vector>
00027 #include <set>
00028 #include <fstream>
00029 #include <algorithm>
00030 #include <functional>
00031 
00032 #include <google/protobuf/io/zero_copy_stream.h>
00033 #include <google/protobuf/io/zero_copy_stream_impl.h>
00034 
00035 #include <drizzled/cached_directory.h>
00036 #include <drizzled/definitions.h>
00037 #include <drizzled/base.h>
00038 #include <drizzled/cursor.h>
00039 #include <drizzled/plugin/storage_engine.h>
00040 #include <drizzled/session.h>
00041 #include <drizzled/error.h>
00042 #include <drizzled/gettext.h>
00043 #include <drizzled/unireg.h>
00044 #include <drizzled/data_home.h>
00045 #include <drizzled/errmsg_print.h>
00046 #include <drizzled/xid.h>
00047 #include <drizzled/sql_table.h>
00048 #include <drizzled/global_charset_info.h>
00049 #include <drizzled/charset.h>
00050 #include <drizzled/internal/my_sys.h>
00051 #include <drizzled/table_proto.h>
00052 #include <drizzled/plugin/event_observer.h>
00053 #include <drizzled/internal_error_handler.h>
00054 #include <drizzled/table/shell.h>
00055 #include <drizzled/message/cache.h>
00056 #include <drizzled/key.h>
00057 
00058 #include <boost/algorithm/string/compare.hpp>
00059 
00060 static bool shutdown_has_begun= false; // Once we put in the container for the vector/etc for engines this will go away.
00061 
00062 namespace drizzled
00063 {
00064 
00065 namespace plugin
00066 {
00067 
00068 static EngineVector vector_of_engines;
00069 static EngineVector vector_of_schema_engines;
00070 
00071 const std::string DEFAULT_STRING("default");
00072 const std::string UNKNOWN_STRING("UNKNOWN");
00073 const std::string DEFAULT_DEFINITION_FILE_EXT(".dfe");
00074 
00075 static std::set<std::string> set_of_table_definition_ext;
00076 
00077 EngineVector &StorageEngine::getSchemaEngines()
00078 {
00079   return vector_of_schema_engines;
00080 }
00081 
00082 StorageEngine::StorageEngine(const std::string name_arg,
00083                              const std::bitset<HTON_BIT_SIZE> &flags_arg) :
00084   Plugin(name_arg, "StorageEngine"),
00085   MonitoredInTransaction(), /* This gives the storage engine a "slot" or ID */
00086   flags(flags_arg)
00087 {
00088 }
00089 
00090 StorageEngine::~StorageEngine()
00091 {
00092 }
00093 
00094 void StorageEngine::setTransactionReadWrite(Session& session)
00095 {
00096   TransactionContext &statement_ctx= session.transaction.stmt;
00097   statement_ctx.markModifiedNonTransData();
00098 }
00099 
00100 
00101 int StorageEngine::renameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
00102 {
00103   int error;
00104   setTransactionReadWrite(session);
00105 
00106   if (unlikely(plugin::EventObserver::beforeRenameTable(session, from, to)))
00107   {
00108     error= ER_EVENT_OBSERVER_PLUGIN;
00109   }
00110   else
00111   {
00112     error =  doRenameTable(session, from, to);
00113     if (unlikely(plugin::EventObserver::afterRenameTable(session, from, to, error)))
00114     {
00115       error= ER_EVENT_OBSERVER_PLUGIN;
00116     }
00117   }
00118   
00119   return error;
00120 }
00121 
00137 int StorageEngine::doDropTable(Session&, const identifier::Table &identifier)
00138                                
00139 {
00140   int error= 0;
00141   int enoent_or_zero= ENOENT;                   // Error if no file was deleted
00142   char buff[FN_REFLEN];
00143 
00144   for (const char **ext= bas_ext(); *ext ; ext++)
00145   {
00146     internal::fn_format(buff, identifier.getPath().c_str(), "", *ext,
00147                         MY_UNPACK_FILENAME|MY_APPEND_EXT);
00148     if (internal::my_delete_with_symlink(buff, MYF(0)))
00149     {
00150       if ((error= errno) != ENOENT)
00151         break;
00152     }
00153     else
00154     {
00155       enoent_or_zero= 0;                        // No error for ENOENT
00156     }
00157 
00158     error= enoent_or_zero;
00159   }
00160   return error;
00161 }
00162 
00163 bool StorageEngine::addPlugin(StorageEngine *engine)
00164 {
00165 
00166   vector_of_engines.push_back(engine);
00167 
00168   if (engine->getTableDefinitionFileExtension().length())
00169   {
00170     assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
00171     set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
00172   }
00173 
00174   if (engine->check_flag(HTON_BIT_SCHEMA_DICTIONARY))
00175     vector_of_schema_engines.push_back(engine);
00176 
00177   return false;
00178 }
00179 
00180 void StorageEngine::removePlugin(StorageEngine *)
00181 {
00182   if (shutdown_has_begun == false)
00183   {
00184     vector_of_engines.clear();
00185     vector_of_schema_engines.clear();
00186 
00187     shutdown_has_begun= true;
00188   }
00189 }
00190 
00191 class FindEngineByName
00192   : public std::unary_function<StorageEngine *, bool>
00193 {
00194   const std::string &predicate;
00195 
00196 public:
00197   explicit FindEngineByName(const std::string &target_arg) :
00198     predicate(target_arg)
00199   {
00200   }
00201 
00202   result_type operator() (argument_type engine)
00203   {
00204     return boost::iequals(engine->getName(), predicate);
00205   }
00206 };
00207 
00208 StorageEngine *StorageEngine::findByName(const std::string &predicate)
00209 {
00210   EngineVector::iterator iter= std::find_if(vector_of_engines.begin(),
00211                                             vector_of_engines.end(),
00212                                             FindEngineByName(predicate));
00213   if (iter != vector_of_engines.end())
00214   {
00215     StorageEngine *engine= *iter;
00216     if (engine->is_user_selectable())
00217       return engine;
00218   }
00219 
00220   return NULL;
00221 }
00222 
00223 StorageEngine *StorageEngine::findByName(Session& session, const std::string &predicate)
00224 {
00225   if (boost::iequals(predicate, DEFAULT_STRING))
00226     return session.getDefaultStorageEngine();
00227 
00228   EngineVector::iterator iter= std::find_if(vector_of_engines.begin(),
00229                                             vector_of_engines.end(),
00230                                             FindEngineByName(predicate));
00231   if (iter != vector_of_engines.end())
00232   {
00233     StorageEngine *engine= *iter;
00234     if (engine->is_user_selectable())
00235       return engine;
00236   }
00237 
00238   return NULL;
00239 }
00240 
00241 class StorageEngineCloseConnection : public std::unary_function<StorageEngine *, void>
00242 {
00243   Session *session;
00244 public:
00245   StorageEngineCloseConnection(Session *session_arg) : session(session_arg) {}
00246   /*
00247     there's no need to rollback here as all transactions must
00248     be rolled back already
00249   */
00250   inline result_type operator() (argument_type engine)
00251   {
00252     if (*session->getEngineData(engine))
00253       engine->close_connection(session);
00254   }
00255 };
00256 
00261 void StorageEngine::closeConnection(Session* session)
00262 {
00263   std::for_each(vector_of_engines.begin(), vector_of_engines.end(),
00264                 StorageEngineCloseConnection(session));
00265 }
00266 
00267 bool StorageEngine::flushLogs(StorageEngine *engine)
00268 {
00269   if (engine == NULL)
00270   {
00271     if (std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
00272                      std::mem_fun(&StorageEngine::flush_logs))
00273         != vector_of_engines.begin())
00274       return true;
00275   }
00276   else
00277   {
00278     if (engine->flush_logs())
00279       return true;
00280   }
00281   return false;
00282 }
00283 
00284 class StorageEngineGetTableDefinition: public std::unary_function<StorageEngine *,bool>
00285 {
00286   Session& session;
00287   const identifier::Table &identifier;
00288   message::Table &table_message;
00289   drizzled::error_t &err;
00290 
00291 public:
00292   StorageEngineGetTableDefinition(Session& session_arg,
00293                                   const identifier::Table &identifier_arg,
00294                                   message::Table &table_message_arg,
00295                                   drizzled::error_t &err_arg) :
00296     session(session_arg), 
00297     identifier(identifier_arg),
00298     table_message(table_message_arg), 
00299     err(err_arg) {}
00300 
00301   result_type operator() (argument_type engine)
00302   {
00303     int ret= engine->doGetTableDefinition(session, identifier, table_message);
00304 
00305     if (ret != ENOENT)
00306       err= static_cast<drizzled::error_t>(ret);
00307 
00308     return err == static_cast<drizzled::error_t>(EEXIST) or err != static_cast<drizzled::error_t>(ENOENT);
00309   }
00310 };
00311 
00312 class StorageEngineDoesTableExist: public std::unary_function<StorageEngine *, bool>
00313 {
00314   Session& session;
00315   const identifier::Table &identifier;
00316 
00317 public:
00318   StorageEngineDoesTableExist(Session& session_arg, const identifier::Table &identifier_arg) :
00319     session(session_arg), 
00320     identifier(identifier_arg) 
00321   { }
00322 
00323   result_type operator() (argument_type engine)
00324   {
00325     return engine->doDoesTableExist(session, identifier);
00326   }
00327 };
00328 
00332 bool plugin::StorageEngine::doesTableExist(Session &session,
00333                                            const identifier::Table &identifier,
00334                                            bool include_temporary_tables)
00335 {
00336   if (include_temporary_tables)
00337   {
00338     if (session.doDoesTableExist(identifier))
00339       return true;
00340   }
00341 
00342   EngineVector::iterator iter=
00343     std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
00344                  StorageEngineDoesTableExist(session, identifier));
00345 
00346   if (iter == vector_of_engines.end())
00347   {
00348     return false;
00349   }
00350 
00351   return true;
00352 }
00353 
00354 bool plugin::StorageEngine::doDoesTableExist(Session&, const drizzled::identifier::Table&)
00355 {
00356   std::cerr << " Engine was called for doDoesTableExist() and does not implement it: " << this->getName() << "\n";
00357   assert(0);
00358   return false;
00359 }
00360 
00361 message::table::shared_ptr StorageEngine::getTableMessage(Session& session,
00362                                                           identifier::Table::const_reference identifier,
00363                                                           bool include_temporary_tables)
00364 {
00365   drizzled::error_t error;
00366   error= static_cast<drizzled::error_t>(ENOENT);
00367 
00368   if (include_temporary_tables)
00369   {
00370     Table *table= session.find_temporary_table(identifier);
00371     if (table)
00372     {
00373       return message::table::shared_ptr(new message::Table(*table->getShare()->getTableMessage()));
00374     }
00375   }
00376 
00377   drizzled::message::table::shared_ptr table_ptr;
00378   if ((table_ptr= drizzled::message::Cache::singleton().find(identifier)))
00379   {
00380     (void)table_ptr;
00381   }
00382 
00383   message::Table message;
00384   EngineVector::iterator iter=
00385     std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
00386                  StorageEngineGetTableDefinition(session, identifier, message, error));
00387 
00388   if (iter == vector_of_engines.end())
00389   {
00390     return message::table::shared_ptr();
00391   }
00392   message::table::shared_ptr table_message(new message::Table(message));
00393 
00394   drizzled::message::Cache::singleton().insert(identifier, table_message);
00395 
00396   return table_message;
00397 }
00398 
00405 class Ha_delete_table_error_handler: public Internal_error_handler
00406 {
00407 public:
00408   Ha_delete_table_error_handler() : Internal_error_handler() {}
00409   virtual bool handle_error(drizzled::error_t sql_errno,
00410                             const char *message,
00411                             DRIZZLE_ERROR::enum_warning_level level,
00412                             Session *session);
00413   char buff[DRIZZLE_ERRMSG_SIZE];
00414 };
00415 
00416 
00417 bool
00418 Ha_delete_table_error_handler::
00419 handle_error(drizzled::error_t ,
00420              const char *message,
00421              DRIZZLE_ERROR::enum_warning_level ,
00422              Session *)
00423 {
00424   /* Grab the error message */
00425   strncpy(buff, message, sizeof(buff)-1);
00426   return true;
00427 }
00428 
00429 class DropTableByIdentifier: public std::unary_function<EngineVector::value_type, bool>
00430 {
00431   Session::reference session;
00432   identifier::Table::const_reference identifier;
00433   drizzled::error_t &error;
00434 
00435 public:
00436 
00437   DropTableByIdentifier(Session::reference session_arg,
00438                         identifier::Table::const_reference identifier_arg,
00439                         drizzled::error_t &error_arg) :
00440     session(session_arg),
00441     identifier(identifier_arg),
00442     error(error_arg)
00443   { }
00444 
00445   result_type operator() (argument_type engine)
00446   {
00447     if (not engine->doDoesTableExist(session, identifier))
00448       return false;
00449 
00450     int local_error= engine->doDropTable(session, identifier);
00451 
00452 
00453     if (not local_error)
00454       return true;
00455 
00456     switch (local_error)
00457     {
00458     case HA_ERR_NO_SUCH_TABLE:
00459     case ENOENT:
00460       error= static_cast<drizzled::error_t>(HA_ERR_NO_SUCH_TABLE);
00461       return false;
00462 
00463     default:
00464       error= static_cast<drizzled::error_t>(local_error);
00465       return true;
00466     }
00467   } 
00468 };
00469 
00470 
00471 bool StorageEngine::dropTable(Session::reference session,
00472                               identifier::Table::const_reference identifier,
00473                               drizzled::error_t &error)
00474 {
00475   error= EE_OK;
00476 
00477   EngineVector::const_iterator iter= std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
00478                                                   DropTableByIdentifier(session, identifier, error));
00479 
00480   if (error)
00481   {
00482     return false;
00483   }
00484   else if (iter == vector_of_engines.end())
00485   {
00486     error= ER_BAD_TABLE_ERROR;
00487     return false;
00488   }
00489 
00490   drizzled::message::Cache::singleton().erase(identifier);
00491 
00492   return true;
00493 }
00494 
00495 bool StorageEngine::dropTable(Session& session,
00496                               const identifier::Table &identifier)
00497 {
00498   drizzled::error_t error;
00499 
00500   if (not dropTable(session, identifier, error))
00501   {
00502     return false;
00503   }
00504 
00505   return true;
00506 }
00507 
00508 bool StorageEngine::dropTable(Session::reference session,
00509                               StorageEngine &engine,
00510                               identifier::Table::const_reference identifier,
00511                               drizzled::error_t &error)
00512 {
00513   error= EE_OK;
00514   engine.setTransactionReadWrite(session);
00515 
00516   assert(identifier.isTmp());
00517   
00518   if (unlikely(plugin::EventObserver::beforeDropTable(session, identifier)))
00519   {
00520     error= ER_EVENT_OBSERVER_PLUGIN;
00521   }
00522   else
00523   {
00524     error= static_cast<drizzled::error_t>(engine.doDropTable(session, identifier));
00525 
00526     if (unlikely(plugin::EventObserver::afterDropTable(session, identifier, error)))
00527     {
00528       error= ER_EVENT_OBSERVER_PLUGIN;
00529     }
00530   }
00531 
00532   drizzled::message::Cache::singleton().erase(identifier);
00533 
00534   if (error)
00535   {
00536     return false;
00537   }
00538 
00539   return true;
00540 }
00541 
00542 
00551 bool StorageEngine::createTable(Session &session,
00552                                 const identifier::Table &identifier,
00553                                 message::Table& table_message)
00554 {
00555   drizzled::error_t error= EE_OK;
00556 
00557   TableShare share(identifier);
00558   table::Shell table(share);
00559   message::Table tmp_proto;
00560 
00561   if (share.parse_table_proto(session, table_message) || share.open_table_from_share(&session, identifier, "", 0, 0, table))
00562   { 
00563     // @note Error occured, we should probably do a little more here.
00564     // ER_CORRUPT_TABLE_DEFINITION,ER_CORRUPT_TABLE_DEFINITION_ENUM 
00565     
00566     my_error(ER_CORRUPT_TABLE_DEFINITION_UNKNOWN, identifier);
00567 
00568     return false;
00569   }
00570   else
00571   {
00572     /* Check for legal operations against the Engine using the proto (if used) */
00573     if (table_message.type() == message::Table::TEMPORARY &&
00574         share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
00575     {
00576       error= HA_ERR_UNSUPPORTED;
00577     }
00578     else if (table_message.type() != message::Table::TEMPORARY &&
00579              share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
00580     {
00581       error= HA_ERR_UNSUPPORTED;
00582     }
00583     else
00584     {
00585       share.storage_engine->setTransactionReadWrite(session);
00586 
00587       error= static_cast<drizzled::error_t>(share.storage_engine->doCreateTable(session,
00588                                                                                 table,
00589                                                                                 identifier,
00590                                                                                 table_message));
00591     }
00592 
00593     if (error == ER_TABLE_PERMISSION_DENIED)
00594     {
00595       my_error(ER_TABLE_PERMISSION_DENIED, identifier);
00596     }
00597     else if (error)
00598     {
00599       std::string path;
00600       identifier.getSQLPath(path);
00601       my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), path.c_str(), error);
00602     }
00603 
00604     table.delete_table();
00605   }
00606 
00607   return(error == EE_OK);
00608 }
00609 
00610 Cursor *StorageEngine::getCursor(Table &arg)
00611 {
00612   return create(arg);
00613 }
00614 
00615 class AddTableIdentifier : 
00616   public std::unary_function<StorageEngine *, void>
00617 {
00618   CachedDirectory &directory;
00619   const identifier::Schema &identifier;
00620   identifier::Table::vector &set_of_identifiers;
00621 
00622 public:
00623 
00624   AddTableIdentifier(CachedDirectory &directory_arg, const identifier::Schema &identifier_arg, identifier::Table::vector &of_names) :
00625     directory(directory_arg),
00626     identifier(identifier_arg),
00627     set_of_identifiers(of_names)
00628   {
00629   }
00630 
00631   result_type operator() (argument_type engine)
00632   {
00633     engine->doGetTableIdentifiers(directory, identifier, set_of_identifiers);
00634   }
00635 };
00636 
00637 
00638 void StorageEngine::getIdentifiers(Session &session, const identifier::Schema &schema_identifier, identifier::Table::vector &set_of_identifiers)
00639 {
00640   CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
00641 
00642   if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
00643   { }
00644   else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
00645   { }
00646   else
00647   {
00648     if (directory.fail())
00649     {
00650       errno= directory.getError();
00651       if (errno == ENOENT)
00652       {
00653         std::string path;
00654         schema_identifier.getSQLPath(path);
00655         my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), path.c_str());
00656       }
00657       else
00658       {
00659         my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
00660       }
00661 
00662       return;
00663     }
00664   }
00665 
00666   std::for_each(vector_of_engines.begin(), vector_of_engines.end(),
00667                 AddTableIdentifier(directory, schema_identifier, set_of_identifiers));
00668 
00669   session.doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
00670 }
00671 
00672 class DropTable: public std::unary_function<identifier::Table&, bool>
00673 {
00674   Session &session;
00675   StorageEngine *engine;
00676 
00677 public:
00678 
00679   DropTable(Session &session_arg, StorageEngine *engine_arg) :
00680     session(session_arg),
00681     engine(engine_arg)
00682   { }
00683 
00684   result_type operator() (argument_type identifier)
00685   {
00686     return engine->doDropTable(session, identifier) == 0;
00687   } 
00688 };
00689 
00690 /* This will later be converted to identifier::Tables */
00691 class DropTables: public std::unary_function<StorageEngine *, void>
00692 {
00693   Session &session;
00694   identifier::Table::vector &table_identifiers;
00695 
00696 public:
00697 
00698   DropTables(Session &session_arg, identifier::Table::vector &table_identifiers_arg) :
00699     session(session_arg),
00700     table_identifiers(table_identifiers_arg)
00701   { }
00702 
00703   result_type operator() (argument_type engine)
00704   {
00705     // True returning from DropTable means the table has been successfully
00706     // deleted, so it should be removed from the list of tables to drop
00707     table_identifiers.erase(std::remove_if(table_identifiers.begin(),
00708                                            table_identifiers.end(),
00709                                            DropTable(session, engine)),
00710                             table_identifiers.end());
00711   }
00712 };
00713 
00714 /*
00715   This only works for engines which use file based DFE.
00716 
00717   Note-> Unlike MySQL, we do not, on purpose, delete files that do not match any engines. 
00718 */
00719 void StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
00720 {
00721   CachedDirectory dir(directory, set_of_table_definition_ext);
00722   identifier::Table::vector table_identifiers;
00723 
00724   if (dir.fail())
00725   {
00726     errno= dir.getError();
00727     my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
00728 
00729     return;
00730   }
00731 
00732   CachedDirectory::Entries files= dir.getEntries();
00733 
00734   for (CachedDirectory::Entries::iterator fileIter= files.begin();
00735        fileIter != files.end(); fileIter++)
00736   {
00737     size_t length;
00738     std::string path;
00739     CachedDirectory::Entry *entry= *fileIter;
00740 
00741     /* We remove the file extension. */
00742     length= entry->filename.length();
00743     entry->filename.resize(length - DEFAULT_DEFINITION_FILE_EXT.length());
00744 
00745     path+= directory;
00746     path+= FN_LIBCHAR;
00747     path+= entry->filename;
00748     message::Table definition;
00749     if (StorageEngine::readTableFile(path, definition))
00750     {
00751       identifier::Table identifier(definition.schema(), definition.name(), path);
00752       table_identifiers.push_back(identifier);
00753     }
00754   }
00755 
00756   std::for_each(vector_of_engines.begin(), vector_of_engines.end(),
00757                 DropTables(session, table_identifiers));
00758 
00759   /*
00760     Now we just clean up anything that might left over.
00761 
00762     We rescan because some of what might have been there should
00763     now be all nice and cleaned up.
00764   */
00765   std::set<std::string> all_exts= set_of_table_definition_ext;
00766 
00767   for (EngineVector::iterator iter= vector_of_engines.begin();
00768        iter != vector_of_engines.end() ; iter++)
00769   {
00770     for (const char **ext= (*iter)->bas_ext(); *ext ; ext++)
00771       all_exts.insert(*ext);
00772   }
00773 
00774   CachedDirectory rescan(directory, all_exts);
00775 
00776   files= rescan.getEntries();
00777   for (CachedDirectory::Entries::iterator fileIter= files.begin();
00778        fileIter != files.end(); fileIter++)
00779   {
00780     std::string path;
00781     CachedDirectory::Entry *entry= *fileIter;
00782 
00783     path+= directory;
00784     path+= FN_LIBCHAR;
00785     path+= entry->filename;
00786 
00787     unlink(path.c_str());
00788   }
00789 }
00790 
00791 
00801 void StorageEngine::print_error(int error, myf errflag, const Table &table) const
00802 {
00803   drizzled::error_t textno= ER_GET_ERRNO;
00804   switch (error) {
00805   case EACCES:
00806     textno=ER_OPEN_AS_READONLY;
00807     break;
00808   case EAGAIN:
00809     textno=ER_FILE_USED;
00810     break;
00811   case ENOENT:
00812     textno=ER_FILE_NOT_FOUND;
00813     break;
00814   case HA_ERR_KEY_NOT_FOUND:
00815   case HA_ERR_NO_ACTIVE_RECORD:
00816   case HA_ERR_END_OF_FILE:
00817     textno=ER_KEY_NOT_FOUND;
00818     break;
00819   case HA_ERR_WRONG_MRG_TABLE_DEF:
00820     textno=ER_WRONG_MRG_TABLE;
00821     break;
00822   case HA_ERR_FOUND_DUPP_KEY:
00823   {
00824     uint32_t key_nr= table.get_dup_key(error);
00825     if ((int) key_nr >= 0)
00826     {
00827       const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
00828 
00829       print_keydup_error(key_nr, err_msg, table);
00830 
00831       return;
00832     }
00833     textno=ER_DUP_KEY;
00834     break;
00835   }
00836   case HA_ERR_FOREIGN_DUPLICATE_KEY:
00837   {
00838     uint32_t key_nr= table.get_dup_key(error);
00839     if ((int) key_nr >= 0)
00840     {
00841       uint32_t max_length;
00842 
00843       /* Write the key in the error message */
00844       char key[MAX_KEY_LENGTH];
00845       String str(key,sizeof(key),system_charset_info);
00846 
00847       /* Table is opened and defined at this point */
00848       key_unpack(&str, &table,(uint32_t) key_nr);
00849       max_length= (DRIZZLE_ERRMSG_SIZE-
00850                    (uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
00851       if (str.length() >= max_length)
00852       {
00853         str.length(max_length-4);
00854         str.append(STRING_WITH_LEN("..."));
00855       }
00856       my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table.getShare()->getTableName(),
00857         str.c_ptr(), key_nr+1);
00858       return;
00859     }
00860     textno= ER_DUP_KEY;
00861     break;
00862   }
00863   case HA_ERR_FOUND_DUPP_UNIQUE:
00864     textno=ER_DUP_UNIQUE;
00865     break;
00866   case HA_ERR_RECORD_CHANGED:
00867     textno=ER_CHECKREAD;
00868     break;
00869   case HA_ERR_CRASHED:
00870     textno=ER_NOT_KEYFILE;
00871     break;
00872   case HA_ERR_WRONG_IN_RECORD:
00873     textno= ER_CRASHED_ON_USAGE;
00874     break;
00875   case HA_ERR_CRASHED_ON_USAGE:
00876     textno=ER_CRASHED_ON_USAGE;
00877     break;
00878   case HA_ERR_NOT_A_TABLE:
00879     textno= static_cast<drizzled::error_t>(error);
00880     break;
00881   case HA_ERR_CRASHED_ON_REPAIR:
00882     textno=ER_CRASHED_ON_REPAIR;
00883     break;
00884   case HA_ERR_OUT_OF_MEM:
00885     textno=ER_OUT_OF_RESOURCES;
00886     break;
00887   case HA_ERR_WRONG_COMMAND:
00888     textno=ER_ILLEGAL_HA;
00889     break;
00890   case HA_ERR_OLD_FILE:
00891     textno=ER_OLD_KEYFILE;
00892     break;
00893   case HA_ERR_UNSUPPORTED:
00894     textno=ER_UNSUPPORTED_EXTENSION;
00895     break;
00896   case HA_ERR_RECORD_FILE_FULL:
00897   case HA_ERR_INDEX_FILE_FULL:
00898     textno=ER_RECORD_FILE_FULL;
00899     break;
00900   case HA_ERR_LOCK_WAIT_TIMEOUT:
00901     textno=ER_LOCK_WAIT_TIMEOUT;
00902     break;
00903   case HA_ERR_LOCK_TABLE_FULL:
00904     textno=ER_LOCK_TABLE_FULL;
00905     break;
00906   case HA_ERR_LOCK_DEADLOCK:
00907     textno=ER_LOCK_DEADLOCK;
00908     break;
00909   case HA_ERR_READ_ONLY_TRANSACTION:
00910     textno=ER_READ_ONLY_TRANSACTION;
00911     break;
00912   case HA_ERR_CANNOT_ADD_FOREIGN:
00913     textno=ER_CANNOT_ADD_FOREIGN;
00914     break;
00915   case HA_ERR_ROW_IS_REFERENCED:
00916   {
00917     String str;
00918     get_error_message(error, &str);
00919     my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
00920     return;
00921   }
00922   case HA_ERR_NO_REFERENCED_ROW:
00923   {
00924     String str;
00925     get_error_message(error, &str);
00926     my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
00927     return;
00928   }
00929   case HA_ERR_TABLE_DEF_CHANGED:
00930     textno=ER_TABLE_DEF_CHANGED;
00931     break;
00932   case HA_ERR_NO_SUCH_TABLE:
00933     {
00934       identifier::Table identifier(table.getShare()->getSchemaName(), table.getShare()->getTableName());
00935       my_error(ER_TABLE_UNKNOWN, identifier);
00936       return;
00937     }
00938   case HA_ERR_RBR_LOGGING_FAILED:
00939     textno= ER_BINLOG_ROW_LOGGING_FAILED;
00940     break;
00941   case HA_ERR_DROP_INDEX_FK:
00942   {
00943     const char *ptr= "???";
00944     uint32_t key_nr= table.get_dup_key(error);
00945     if ((int) key_nr >= 0)
00946       ptr= table.key_info[key_nr].name;
00947     my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
00948     return;
00949   }
00950   case HA_ERR_TABLE_NEEDS_UPGRADE:
00951     textno=ER_TABLE_NEEDS_UPGRADE;
00952     break;
00953   case HA_ERR_TABLE_READONLY:
00954     textno= ER_OPEN_AS_READONLY;
00955     break;
00956   case HA_ERR_AUTOINC_READ_FAILED:
00957     textno= ER_AUTOINC_READ_FAILED;
00958     break;
00959   case HA_ERR_AUTOINC_ERANGE:
00960     textno= ER_WARN_DATA_OUT_OF_RANGE;
00961     break;
00962   case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
00963     my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
00964                ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
00965     return;
00966   default:
00967     {
00968       /* 
00969         The error was "unknown" to this function.
00970         Ask Cursor if it has got a message for this error 
00971       */
00972       bool temporary= false;
00973       String str;
00974       temporary= get_error_message(error, &str);
00975       if (!str.is_empty())
00976       {
00977         const char* engine_name= getName().c_str();
00978         if (temporary)
00979           my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(),
00980                    engine_name);
00981         else
00982           my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
00983       }
00984       else
00985       {
00986         my_error(ER_GET_ERRNO,errflag,error);
00987       }
00988       return;
00989     }
00990   }
00991 
00992   my_error(textno, errflag, table.getShare()->getTableName(), error);
00993 }
00994 
00995 
01005 bool StorageEngine::get_error_message(int , String* ) const
01006 {
01007   return false;
01008 }
01009 
01010 
01011 void StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, const Table &table) const
01012 {
01013   /* Write the duplicated key in the error message */
01014   char key[MAX_KEY_LENGTH];
01015   String str(key,sizeof(key),system_charset_info);
01016 
01017   if (key_nr == MAX_KEY)
01018   {
01019     /* Key is unknown */
01020     str.copy("", 0, system_charset_info);
01021     my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
01022   }
01023   else
01024   {
01025     /* Table is opened and defined at this point */
01026     key_unpack(&str, &table, (uint32_t) key_nr);
01027     uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
01028     if (str.length() >= max_length)
01029     {
01030       str.length(max_length-4);
01031       str.append(STRING_WITH_LEN("..."));
01032     }
01033     my_printf_error(ER_DUP_ENTRY, msg,
01034         MYF(0), str.c_ptr(), table.key_info[key_nr].name);
01035   }
01036 }
01037 
01038 
01039 int StorageEngine::deleteDefinitionFromPath(const identifier::Table &identifier)
01040 {
01041   std::string path(identifier.getPath());
01042 
01043   path.append(DEFAULT_DEFINITION_FILE_EXT);
01044 
01045   return internal::my_delete(path.c_str(), MYF(0));
01046 }
01047 
01048 int StorageEngine::renameDefinitionFromPath(const identifier::Table &dest, const identifier::Table &src)
01049 {
01050   message::Table table_message;
01051   std::string src_path(src.getPath());
01052   std::string dest_path(dest.getPath());
01053 
01054   src_path.append(DEFAULT_DEFINITION_FILE_EXT);
01055   dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
01056 
01057   bool was_read= StorageEngine::readTableFile(src_path.c_str(), table_message);
01058 
01059   if (not was_read)
01060   {
01061     return ENOENT;
01062   }
01063 
01064   dest.copyToTableMessage(table_message);
01065 
01066   int error= StorageEngine::writeDefinitionFromPath(dest, table_message);
01067 
01068   if (not error)
01069   {
01070     if (unlink(src_path.c_str()))
01071       perror(src_path.c_str());
01072   }
01073 
01074   return error;
01075 }
01076 
01077 int StorageEngine::writeDefinitionFromPath(const identifier::Table &identifier, const message::Table &table_message)
01078 {
01079   char definition_file_tmp[FN_REFLEN];
01080   std::string file_name(identifier.getPath());
01081 
01082   file_name.append(DEFAULT_DEFINITION_FILE_EXT);
01083 
01084   snprintf(definition_file_tmp, sizeof(definition_file_tmp), "%sXXXXXX", file_name.c_str());
01085 
01086   int fd= mkstemp(definition_file_tmp);
01087 
01088   if (fd == -1)
01089   {
01090     perror(definition_file_tmp);
01091     return errno;
01092   }
01093 
01094   google::protobuf::io::ZeroCopyOutputStream* output=
01095     new google::protobuf::io::FileOutputStream(fd);
01096 
01097   bool success;
01098 
01099   try
01100   {
01101     success= table_message.SerializeToZeroCopyStream(output);
01102   }
01103   catch (...)
01104   {
01105     success= false;
01106   }
01107 
01108   if (not success)
01109   {
01110     std::string error_message;
01111     identifier.getSQLPath(error_message);
01112 
01113     my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
01114              error_message.c_str(),
01115              table_message.InitializationErrorString().c_str());
01116     delete output;
01117 
01118     if (close(fd) == -1)
01119       perror(definition_file_tmp);
01120 
01121     if (unlink(definition_file_tmp) == -1)
01122       perror(definition_file_tmp);
01123 
01124     return ER_CORRUPT_TABLE_DEFINITION;
01125   }
01126 
01127   delete output;
01128 
01129   if (close(fd) == -1)
01130   {
01131     int error= errno;
01132     perror(definition_file_tmp);
01133 
01134     if (unlink(definition_file_tmp))
01135       perror(definition_file_tmp);
01136 
01137     return error;
01138   }
01139 
01140   if (rename(definition_file_tmp, file_name.c_str()) == -1)
01141   {
01142     int error= errno;
01143     perror(definition_file_tmp);
01144 
01145     if (unlink(definition_file_tmp))
01146       perror(definition_file_tmp);
01147 
01148     return error;
01149   }
01150 
01151   return 0;
01152 }
01153 
01154 class CanCreateTable: public std::unary_function<StorageEngine *, bool>
01155 {
01156   const identifier::Table &identifier;
01157 
01158 public:
01159   CanCreateTable(const identifier::Table &identifier_arg) :
01160     identifier(identifier_arg)
01161   { }
01162 
01163   result_type operator() (argument_type engine)
01164   {
01165     return not engine->doCanCreateTable(identifier);
01166   }
01167 };
01168 
01169 
01173 bool StorageEngine::canCreateTable(const identifier::Table &identifier)
01174 {
01175   EngineVector::iterator iter=
01176     std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
01177                  CanCreateTable(identifier));
01178 
01179   if (iter == vector_of_engines.end())
01180   {
01181     return true;
01182   }
01183 
01184   return false;
01185 }
01186 
01187 bool StorageEngine::readTableFile(const std::string &path, message::Table &table_message)
01188 {
01189   std::fstream input(path.c_str(), std::ios::in | std::ios::binary);
01190 
01191   if (input.good())
01192   {
01193     try {
01194       if (table_message.ParseFromIstream(&input))
01195       {
01196         return true;
01197       }
01198     }
01199     catch (...)
01200     {
01201       my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
01202                table_message.name().empty() ? path.c_str() : table_message.name().c_str(),
01203                table_message.InitializationErrorString().empty() ? "": table_message.InitializationErrorString().c_str());
01204     }
01205   }
01206   else
01207   {
01208     perror(path.c_str());
01209   }
01210 
01211   return false;
01212 }
01213 
01214 std::ostream& operator<<(std::ostream& output, const StorageEngine &engine)
01215 {
01216   output << "StorageEngine:(";
01217   output <<  engine.getName();
01218   output << ")";
01219 
01220   return output;
01221 }
01222 
01223 } /* namespace plugin */
01224 } /* namespace drizzled */