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/data_home.h>
00044 #include <drizzled/errmsg_print.h>
00045 #include <drizzled/xid.h>
00046 #include <drizzled/sql_table.h>
00047 #include <drizzled/charset.h>
00048 #include <drizzled/internal/my_sys.h>
00049 #include <drizzled/table_proto.h>
00050 #include <drizzled/plugin/event_observer.h>
00051 #include <drizzled/table/shell.h>
00052 #include <drizzled/message/cache.h>
00053 #include <drizzled/key.h>
00054 #include <drizzled/session/transactions.h>
00055 #include <drizzled/open_tables_state.h>
00056 
00057 #include <boost/algorithm/string/compare.hpp>
00058 
00059 static bool shutdown_has_begun= false; // Once we put in the container for the vector/etc for engines this will go away.
00060 
00061 namespace drizzled {
00062 namespace plugin {
00063 
00064 static EngineVector g_engines;
00065 static EngineVector g_schema_engines;
00066 
00067 const std::string DEFAULT_STRING("default");
00068 const std::string UNKNOWN_STRING("UNKNOWN");
00069 const std::string DEFAULT_DEFINITION_FILE_EXT(".dfe");
00070 
00071 static std::set<std::string> set_of_table_definition_ext;
00072 
00073 EngineVector &StorageEngine::getSchemaEngines()
00074 {
00075   return g_schema_engines;
00076 }
00077 
00078 StorageEngine::StorageEngine(const std::string &name_arg,
00079                              const std::bitset<HTON_BIT_SIZE> &flags_arg) :
00080   Plugin(name_arg, "StorageEngine"),
00081   MonitoredInTransaction(), /* This gives the storage engine a "slot" or ID */
00082   flags(flags_arg)
00083 {
00084 }
00085 
00086 StorageEngine::~StorageEngine()
00087 {
00088 }
00089 
00090 void StorageEngine::setTransactionReadWrite(Session& session)
00091 {
00092   TransactionContext &statement_ctx= session.transaction.stmt;
00093   statement_ctx.markModifiedNonTransData();
00094 }
00095 
00096 int StorageEngine::renameTable(Session &session, const identifier::Table &from, const identifier::Table &to)
00097 {
00098   setTransactionReadWrite(session);
00099   if (unlikely(plugin::EventObserver::beforeRenameTable(session, from, to)))
00100     return ER_EVENT_OBSERVER_PLUGIN;
00101   int error= doRenameTable(session, from, to);
00102   if (unlikely(plugin::EventObserver::afterRenameTable(session, from, to, error)))
00103     error= ER_EVENT_OBSERVER_PLUGIN;
00104   return error;
00105 }
00106 
00122 int StorageEngine::doDropTable(Session&, const identifier::Table &identifier)
00123 {
00124   int error= 0;
00125   int enoent_or_zero= ENOENT;                   // Error if no file was deleted
00126   char buff[FN_REFLEN];
00127 
00128   for (const char **ext= bas_ext(); *ext ; ext++)
00129   {
00130     internal::fn_format(buff, identifier.getPath().c_str(), "", *ext,
00131                         MY_UNPACK_FILENAME|MY_APPEND_EXT);
00132     if (internal::my_delete_with_symlink(buff, MYF(0)))
00133     {
00134       if ((error= errno) != ENOENT)
00135         break;
00136     }
00137     else
00138     {
00139       enoent_or_zero= 0;                        // No error for ENOENT
00140     }
00141 
00142     error= enoent_or_zero;
00143   }
00144   return error;
00145 }
00146 
00147 bool StorageEngine::addPlugin(StorageEngine *engine)
00148 {
00149   g_engines.push_back(engine);
00150 
00151   if (engine->getTableDefinitionFileExtension().length())
00152   {
00153     assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
00154     set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
00155   }
00156 
00157   if (engine->check_flag(HTON_BIT_SCHEMA_DICTIONARY))
00158     g_schema_engines.push_back(engine);
00159 
00160   return false;
00161 }
00162 
00163 void StorageEngine::removePlugin(StorageEngine *)
00164 {
00165   if (shutdown_has_begun)
00166     return;
00167   shutdown_has_begun= true;
00168   g_engines.clear();
00169   g_schema_engines.clear();
00170 }
00171 
00172 StorageEngine *StorageEngine::findByName(const std::string &predicate)
00173 {
00174   BOOST_FOREACH(EngineVector::reference it, g_engines)
00175   {
00176     if (not boost::iequals(it->getName(), predicate))
00177       continue;
00178     if (it->is_user_selectable())
00179       return it;
00180     break;
00181   }
00182   return NULL;
00183 }
00184 
00185 StorageEngine *StorageEngine::findByName(Session& session, const std::string &predicate)
00186 {
00187   if (boost::iequals(predicate, DEFAULT_STRING))
00188     return session.getDefaultStorageEngine();
00189   return findByName(predicate);
00190 }
00191 
00196 void StorageEngine::closeConnection(Session& session)
00197 {
00198   BOOST_FOREACH(EngineVector::reference it, g_engines)
00199   {
00200     if (*session.getEngineData(it))
00201       it->close_connection(&session);
00202   }
00203 }
00204 
00205 bool StorageEngine::flushLogs(StorageEngine *engine)
00206 {
00207   if (not engine)
00208   {
00209     if (std::find_if(g_engines.begin(), g_engines.end(), std::mem_fun(&StorageEngine::flush_logs))
00210         != g_engines.begin()) // Shouldn't this be .end()?
00211       return true;
00212   }
00213   else if (engine->flush_logs())
00214     return true;
00215   return false;
00216 }
00217 
00218 class StorageEngineGetTableDefinition: public std::unary_function<StorageEngine *,bool>
00219 {
00220   Session& session;
00221   const identifier::Table &identifier;
00222   message::Table &table_message;
00223   drizzled::error_t &err;
00224 
00225 public:
00226   StorageEngineGetTableDefinition(Session& session_arg,
00227                                   const identifier::Table &identifier_arg,
00228                                   message::Table &table_message_arg,
00229                                   drizzled::error_t &err_arg) :
00230     session(session_arg), 
00231     identifier(identifier_arg),
00232     table_message(table_message_arg), 
00233     err(err_arg) {}
00234 
00235   result_type operator() (argument_type engine)
00236   {
00237     int ret= engine->doGetTableDefinition(session, identifier, table_message);
00238 
00239     if (ret != ENOENT)
00240       err= static_cast<drizzled::error_t>(ret);
00241 
00242     return err == static_cast<drizzled::error_t>(EEXIST) or err != static_cast<drizzled::error_t>(ENOENT);
00243   }
00244 };
00245 
00249 bool plugin::StorageEngine::doesTableExist(Session &session,
00250                                            const identifier::Table &identifier,
00251                                            bool include_temporary_tables)
00252 {
00253   if (include_temporary_tables && session.open_tables.doDoesTableExist(identifier))
00254       return true;
00255   BOOST_FOREACH(EngineVector::reference it, g_engines)
00256   {
00257     if (it->doDoesTableExist(session, identifier))
00258       return true;
00259   }
00260   return false;
00261 }
00262 
00263 bool plugin::StorageEngine::doDoesTableExist(Session&, const drizzled::identifier::Table&)
00264 {
00265   std::cerr << " Engine was called for doDoesTableExist() and does not implement it: " << getName() << "\n";
00266   assert(0);
00267   return false;
00268 }
00269 
00270 message::table::shared_ptr StorageEngine::getTableMessage(Session& session,
00271                                                           const identifier::Table& identifier,
00272                                                           bool include_temporary_tables)
00273 {
00274   drizzled::error_t error= static_cast<drizzled::error_t>(ENOENT);
00275   if (include_temporary_tables)
00276   {
00277     if (Table *table= session.open_tables.find_temporary_table(identifier))
00278     {
00279       return message::table::shared_ptr(new message::Table(*table->getShare()->getTableMessage()));
00280     }
00281   }
00282 
00283   drizzled::message::table::shared_ptr table_ptr;
00284   if ((table_ptr= drizzled::message::Cache::singleton().find(identifier)))
00285   {
00286     (void)table_ptr;
00287   }
00288 
00289   message::Table message;
00290   EngineVector::iterator iter= std::find_if(g_engines.begin(), g_engines.end(), 
00291     StorageEngineGetTableDefinition(session, identifier, message, error));
00292 
00293   if (iter == g_engines.end())
00294   {
00295     return message::table::shared_ptr();
00296   }
00297   message::table::shared_ptr table_message(new message::Table(message));
00298 
00299   drizzled::message::Cache::singleton().insert(identifier, table_message);
00300 
00301   return table_message;
00302 }
00303 
00304 class DropTableByIdentifier: public std::unary_function<EngineVector::value_type, bool>
00305 {
00306   Session& session;
00307   const identifier::Table& identifier;
00308   drizzled::error_t &error;
00309 
00310 public:
00311 
00312   DropTableByIdentifier(Session& session_arg,
00313                         const identifier::Table& identifier_arg,
00314                         drizzled::error_t &error_arg) :
00315     session(session_arg),
00316     identifier(identifier_arg),
00317     error(error_arg)
00318   { }
00319 
00320   result_type operator() (argument_type engine)
00321   {
00322     if (not engine->doDoesTableExist(session, identifier))
00323       return false;
00324 
00325     int local_error= engine->doDropTable(session, identifier);
00326 
00327 
00328     if (not local_error)
00329       return true;
00330 
00331     switch (local_error)
00332     {
00333     case HA_ERR_NO_SUCH_TABLE:
00334     case ENOENT:
00335       error= static_cast<drizzled::error_t>(HA_ERR_NO_SUCH_TABLE);
00336       return false;
00337 
00338     default:
00339       error= static_cast<drizzled::error_t>(local_error);
00340       return true;
00341     }
00342   } 
00343 };
00344 
00345 
00346 bool StorageEngine::dropTable(Session& session,
00347                               const identifier::Table& identifier,
00348                               drizzled::error_t &error)
00349 {
00350   error= EE_OK;
00351 
00352   EngineVector::const_iterator iter= std::find_if(g_engines.begin(), g_engines.end(),
00353                                                   DropTableByIdentifier(session, identifier, error));
00354 
00355   if (error)
00356   {
00357     return false;
00358   }
00359   else if (iter == g_engines.end())
00360   {
00361     error= ER_BAD_TABLE_ERROR;
00362     return false;
00363   }
00364 
00365   drizzled::message::Cache::singleton().erase(identifier);
00366 
00367   return true;
00368 }
00369 
00370 bool StorageEngine::dropTable(Session& session,
00371                               const identifier::Table &identifier)
00372 {
00373   drizzled::error_t error;
00374   return dropTable(session, identifier, error);
00375 }
00376 
00377 bool StorageEngine::dropTable(Session& session,
00378                               StorageEngine &engine,
00379                               const identifier::Table& identifier,
00380                               drizzled::error_t &error)
00381 {
00382   error= EE_OK;
00383   engine.setTransactionReadWrite(session);
00384 
00385   assert(identifier.isTmp());
00386   
00387   if (unlikely(plugin::EventObserver::beforeDropTable(session, identifier)))
00388   {
00389     error= ER_EVENT_OBSERVER_PLUGIN;
00390   }
00391   else
00392   {
00393     error= static_cast<drizzled::error_t>(engine.doDropTable(session, identifier));
00394 
00395     if (unlikely(plugin::EventObserver::afterDropTable(session, identifier, error)))
00396     {
00397       error= ER_EVENT_OBSERVER_PLUGIN;
00398     }
00399   }
00400   drizzled::message::Cache::singleton().erase(identifier);
00401   return not error;
00402 }
00403 
00404 
00413 bool StorageEngine::createTable(Session &session,
00414                                 const identifier::Table &identifier,
00415                                 message::Table& table_message)
00416 {
00417   drizzled::error_t error= EE_OK;
00418 
00419   TableShare share(identifier);
00420   table::Shell table(share);
00421   message::Table tmp_proto;
00422 
00423   if (share.parse_table_proto(session, table_message) || share.open_table_from_share(&session, identifier, "", 0, 0, table))
00424   { 
00425     // @note Error occured, we should probably do a little more here.
00426     // ER_CORRUPT_TABLE_DEFINITION,ER_CORRUPT_TABLE_DEFINITION_ENUM 
00427     
00428     my_error(ER_CORRUPT_TABLE_DEFINITION_UNKNOWN, identifier);
00429 
00430     return false;
00431   }
00432   else
00433   {
00434     /* Check for legal operations against the Engine using the proto (if used) */
00435     if (table_message.type() == message::Table::TEMPORARY &&
00436         share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
00437     {
00438       error= HA_ERR_UNSUPPORTED;
00439     }
00440     else if (table_message.type() != message::Table::TEMPORARY &&
00441              share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
00442     {
00443       error= HA_ERR_UNSUPPORTED;
00444     }
00445     else
00446     {
00447       share.storage_engine->setTransactionReadWrite(session);
00448 
00449       error= static_cast<drizzled::error_t>(share.storage_engine->doCreateTable(session,
00450                                                                                 table,
00451                                                                                 identifier,
00452                                                                                 table_message));
00453     }
00454 
00455     if (error == ER_TABLE_PERMISSION_DENIED)
00456       my_error(ER_TABLE_PERMISSION_DENIED, identifier);
00457     else if (error)
00458       my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), identifier.getSQLPath().c_str(), error);
00459     table.delete_table();
00460   }
00461   return(error == EE_OK);
00462 }
00463 
00464 Cursor *StorageEngine::getCursor(Table &arg)
00465 {
00466   return create(arg);
00467 }
00468 
00469 void StorageEngine::getIdentifiers(Session &session, const identifier::Schema &schema_identifier, identifier::table::vector &set_of_identifiers)
00470 {
00471   CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
00472 
00473   if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
00474   { 
00475   }
00476   else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
00477   { 
00478   }
00479   else if (directory.fail())
00480   {
00481     errno= directory.getError();
00482     if (errno == ENOENT)
00483       my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), schema_identifier.getSQLPath().c_str());
00484     else
00485       my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
00486     return;
00487   }
00488 
00489   BOOST_FOREACH(EngineVector::reference it, g_engines)
00490     it->doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
00491 
00492   session.open_tables.doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
00493 }
00494 
00495 class DropTable: public std::unary_function<identifier::Table&, bool>
00496 {
00497   Session &session;
00498   StorageEngine *engine;
00499 
00500 public:
00501 
00502   DropTable(Session &session_arg, StorageEngine *engine_arg) :
00503     session(session_arg),
00504     engine(engine_arg)
00505   { }
00506 
00507   result_type operator() (argument_type identifier)
00508   {
00509     return engine->doDropTable(session, identifier) == 0;
00510   } 
00511 };
00512 
00513 /*
00514   This only works for engines which use file based DFE.
00515 
00516   Note-> Unlike MySQL, we do not, on purpose, delete files that do not match any engines. 
00517 */
00518 void StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
00519 {
00520   CachedDirectory dir(directory, set_of_table_definition_ext);
00521   identifier::table::vector table_identifiers;
00522 
00523   if (dir.fail())
00524   {
00525     errno= dir.getError();
00526     my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
00527 
00528     return;
00529   }
00530 
00531   CachedDirectory::Entries files= dir.getEntries();
00532 
00533   for (CachedDirectory::Entries::iterator fileIter= files.begin();
00534        fileIter != files.end(); fileIter++)
00535   {
00536     size_t length;
00537     std::string path;
00538     CachedDirectory::Entry *entry= *fileIter;
00539 
00540     /* We remove the file extension. */
00541     length= entry->filename.length();
00542     entry->filename.resize(length - DEFAULT_DEFINITION_FILE_EXT.length());
00543 
00544     path+= directory;
00545     path+= FN_LIBCHAR;
00546     path+= entry->filename;
00547     message::Table definition;
00548     if (StorageEngine::readTableFile(path, definition))
00549     {
00550       identifier::Table identifier(definition.schema(), definition.name(), path);
00551       table_identifiers.push_back(identifier);
00552     }
00553   }
00554 
00555   BOOST_FOREACH(EngineVector::reference it, g_engines)
00556   {
00557     table_identifiers.erase(std::remove_if(table_identifiers.begin(), table_identifiers.end(), DropTable(session, it)),
00558       table_identifiers.end());
00559   }
00560 
00561   /*
00562     Now we just clean up anything that might left over.
00563 
00564     We rescan because some of what might have been there should
00565     now be all nice and cleaned up.
00566   */
00567   std::set<std::string> all_exts= set_of_table_definition_ext;
00568 
00569   for (EngineVector::iterator iter= g_engines.begin();
00570        iter != g_engines.end() ; iter++)
00571   {
00572     for (const char **ext= (*iter)->bas_ext(); *ext ; ext++)
00573       all_exts.insert(*ext);
00574   }
00575 
00576   CachedDirectory rescan(directory, all_exts);
00577 
00578   files= rescan.getEntries();
00579   for (CachedDirectory::Entries::iterator fileIter= files.begin();
00580        fileIter != files.end(); fileIter++)
00581   {
00582     std::string path;
00583     CachedDirectory::Entry *entry= *fileIter;
00584 
00585     path+= directory;
00586     path+= FN_LIBCHAR;
00587     path+= entry->filename;
00588 
00589     unlink(path.c_str());
00590   }
00591 }
00592 
00593 
00603 void StorageEngine::print_error(int error, myf errflag, const Table &table) const
00604 {
00605   drizzled::error_t textno= ER_GET_ERRNO;
00606   switch (error) {
00607   case EACCES:
00608     textno=ER_OPEN_AS_READONLY;
00609     break;
00610   case EAGAIN:
00611     textno=ER_FILE_USED;
00612     break;
00613   case ENOENT:
00614     textno=ER_FILE_NOT_FOUND;
00615     break;
00616   case HA_ERR_KEY_NOT_FOUND:
00617   case HA_ERR_NO_ACTIVE_RECORD:
00618   case HA_ERR_END_OF_FILE:
00619     textno=ER_KEY_NOT_FOUND;
00620     break;
00621   case HA_ERR_WRONG_MRG_TABLE_DEF:
00622     textno=ER_WRONG_MRG_TABLE;
00623     break;
00624   case HA_ERR_FOUND_DUPP_KEY:
00625   {
00626     uint32_t key_nr= table.get_dup_key(error);
00627     if ((int) key_nr >= 0)
00628     {
00629       const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
00630 
00631       print_keydup_error(key_nr, err_msg, table);
00632 
00633       return;
00634     }
00635     textno=ER_DUP_KEY;
00636     break;
00637   }
00638   case HA_ERR_FOREIGN_DUPLICATE_KEY:
00639   {
00640     uint32_t key_nr= table.get_dup_key(error);
00641     if ((int) key_nr >= 0)
00642     {
00643       uint32_t max_length;
00644 
00645       /* Write the key in the error message */
00646       char key[MAX_KEY_LENGTH];
00647       String str(key,sizeof(key),system_charset_info);
00648 
00649       /* Table is opened and defined at this point */
00650       key_unpack(&str, &table,(uint32_t) key_nr);
00651       max_length= (DRIZZLE_ERRMSG_SIZE-
00652                    (uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
00653       if (str.length() >= max_length)
00654       {
00655         str.length(max_length-4);
00656         str.append(STRING_WITH_LEN("..."));
00657       }
00658       my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table.getShare()->getTableName(),
00659         str.c_ptr(), key_nr+1);
00660       return;
00661     }
00662     textno= ER_DUP_KEY;
00663     break;
00664   }
00665   case HA_ERR_FOUND_DUPP_UNIQUE:
00666     textno=ER_DUP_UNIQUE;
00667     break;
00668   case HA_ERR_RECORD_CHANGED:
00669     textno=ER_CHECKREAD;
00670     break;
00671   case HA_ERR_CRASHED:
00672     textno=ER_NOT_KEYFILE;
00673     break;
00674   case HA_ERR_WRONG_IN_RECORD:
00675     textno= ER_CRASHED_ON_USAGE;
00676     break;
00677   case HA_ERR_CRASHED_ON_USAGE:
00678     textno=ER_CRASHED_ON_USAGE;
00679     break;
00680   case HA_ERR_NOT_A_TABLE:
00681     textno= static_cast<drizzled::error_t>(error);
00682     break;
00683   case HA_ERR_CRASHED_ON_REPAIR:
00684     textno=ER_CRASHED_ON_REPAIR;
00685     break;
00686   case HA_ERR_OUT_OF_MEM:
00687     textno=ER_OUT_OF_RESOURCES;
00688     break;
00689   case HA_ERR_WRONG_COMMAND:
00690     textno=ER_ILLEGAL_HA;
00691     break;
00692   case HA_ERR_OLD_FILE:
00693     textno=ER_OLD_KEYFILE;
00694     break;
00695   case HA_ERR_UNSUPPORTED:
00696     textno=ER_UNSUPPORTED_EXTENSION;
00697     break;
00698   case HA_ERR_RECORD_FILE_FULL:
00699   case HA_ERR_INDEX_FILE_FULL:
00700     textno=ER_RECORD_FILE_FULL;
00701     break;
00702   case HA_ERR_LOCK_WAIT_TIMEOUT:
00703     textno=ER_LOCK_WAIT_TIMEOUT;
00704     break;
00705   case HA_ERR_LOCK_TABLE_FULL:
00706     textno=ER_LOCK_TABLE_FULL;
00707     break;
00708   case HA_ERR_LOCK_DEADLOCK:
00709     textno=ER_LOCK_DEADLOCK;
00710     break;
00711   case HA_ERR_READ_ONLY_TRANSACTION:
00712     textno=ER_READ_ONLY_TRANSACTION;
00713     break;
00714   case HA_ERR_CANNOT_ADD_FOREIGN:
00715     textno=ER_CANNOT_ADD_FOREIGN;
00716     break;
00717   case HA_ERR_ROW_IS_REFERENCED:
00718   {
00719     String str;
00720     get_error_message(error, &str);
00721     my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_str());
00722     return;
00723   }
00724   case HA_ERR_NO_REFERENCED_ROW:
00725   {
00726     String str;
00727     get_error_message(error, &str);
00728     my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_str());
00729     return;
00730   }
00731   case HA_ERR_TABLE_DEF_CHANGED:
00732     textno=ER_TABLE_DEF_CHANGED;
00733     break;
00734   case HA_ERR_NO_SUCH_TABLE:
00735     {
00736       identifier::Table identifier(table.getShare()->getSchemaName(), table.getShare()->getTableName());
00737       my_error(ER_TABLE_UNKNOWN, identifier);
00738       return;
00739     }
00740   case HA_ERR_RBR_LOGGING_FAILED:
00741     textno= ER_BINLOG_ROW_LOGGING_FAILED;
00742     break;
00743   case HA_ERR_DROP_INDEX_FK:
00744   {
00745     const char *ptr= "???";
00746     uint32_t key_nr= table.get_dup_key(error);
00747     if ((int) key_nr >= 0)
00748       ptr= table.key_info[key_nr].name;
00749     my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
00750     return;
00751   }
00752   case HA_ERR_TABLE_NEEDS_UPGRADE:
00753     textno=ER_TABLE_NEEDS_UPGRADE;
00754     break;
00755   case HA_ERR_TABLE_READONLY:
00756     textno= ER_OPEN_AS_READONLY;
00757     break;
00758   case HA_ERR_AUTOINC_READ_FAILED:
00759     textno= ER_AUTOINC_READ_FAILED;
00760     break;
00761   case HA_ERR_AUTOINC_ERANGE:
00762     textno= ER_WARN_DATA_OUT_OF_RANGE;
00763     break;
00764   case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
00765     my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
00766     return;
00767   default:
00768     {
00769       /* 
00770         The error was "unknown" to this function.
00771         Ask Cursor if it has got a message for this error 
00772       */
00773       bool temporary= false;
00774       String str;
00775       temporary= get_error_message(error, &str);
00776       if (!str.empty())
00777       {
00778         const char* engine_name= getName().c_str();
00779         if (temporary)
00780           my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(), engine_name);
00781         else
00782           my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
00783       }
00784       else
00785       {
00786         my_error(ER_GET_ERRNO,errflag,error);
00787       }
00788       return;
00789     }
00790   }
00791 
00792   my_error(textno, errflag, table.getShare()->getTableName(), error);
00793 }
00794 
00795 
00805 bool StorageEngine::get_error_message(int , String* ) const
00806 {
00807   return false;
00808 }
00809 
00810 
00811 void StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, const Table &table) const
00812 {
00813   /* Write the duplicated key in the error message */
00814   char key[MAX_KEY_LENGTH];
00815   String str(key,sizeof(key),system_charset_info);
00816 
00817   if (key_nr == MAX_KEY)
00818   {
00819     /* Key is unknown */
00820     str.copy("", 0, system_charset_info);
00821     my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
00822   }
00823   else
00824   {
00825     /* Table is opened and defined at this point */
00826     key_unpack(&str, &table, (uint32_t) key_nr);
00827     uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
00828     if (str.length() >= max_length)
00829     {
00830       str.length(max_length-4);
00831       str.append(STRING_WITH_LEN("..."));
00832     }
00833     my_printf_error(ER_DUP_ENTRY, msg,
00834         MYF(0), str.c_ptr(), table.key_info[key_nr].name);
00835   }
00836 }
00837 
00838 
00839 int StorageEngine::deleteDefinitionFromPath(const identifier::Table &identifier)
00840 {
00841   std::string path(identifier.getPath());
00842 
00843   path.append(DEFAULT_DEFINITION_FILE_EXT);
00844 
00845   return internal::my_delete(path.c_str(), MYF(0));
00846 }
00847 
00848 int StorageEngine::renameDefinitionFromPath(const identifier::Table &dest, const identifier::Table &src)
00849 {
00850   message::Table table_message;
00851   std::string src_path(src.getPath());
00852   std::string dest_path(dest.getPath());
00853 
00854   src_path.append(DEFAULT_DEFINITION_FILE_EXT);
00855   dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
00856 
00857   bool was_read= StorageEngine::readTableFile(src_path.c_str(), table_message);
00858 
00859   if (not was_read)
00860   {
00861     return ENOENT;
00862   }
00863 
00864   dest.copyToTableMessage(table_message);
00865 
00866   int error= StorageEngine::writeDefinitionFromPath(dest, table_message);
00867 
00868   if (not error)
00869   {
00870     if (unlink(src_path.c_str()))
00871       perror(src_path.c_str());
00872   }
00873 
00874   return error;
00875 }
00876 
00877 int StorageEngine::writeDefinitionFromPath(const identifier::Table &identifier, const message::Table &table_message)
00878 {
00879   char definition_file_tmp[FN_REFLEN];
00880   std::string file_name(identifier.getPath());
00881 
00882   file_name.append(DEFAULT_DEFINITION_FILE_EXT);
00883 
00884   snprintf(definition_file_tmp, sizeof(definition_file_tmp), "%sXXXXXX", file_name.c_str());
00885 
00886   int fd= mkstemp(definition_file_tmp);
00887 
00888   if (fd == -1)
00889   {
00890     perror(definition_file_tmp);
00891     return errno;
00892   }
00893 
00894   google::protobuf::io::ZeroCopyOutputStream* output=
00895     new google::protobuf::io::FileOutputStream(fd);
00896 
00897   bool success;
00898 
00899   try
00900   {
00901     success= table_message.SerializeToZeroCopyStream(output);
00902   }
00903   catch (...)
00904   {
00905     success= false;
00906   }
00907 
00908   if (not success)
00909   {
00910     my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), identifier.getSQLPath().c_str(), table_message.InitializationErrorString().c_str());
00911     delete output;
00912 
00913     if (close(fd) == -1)
00914       perror(definition_file_tmp);
00915 
00916     if (unlink(definition_file_tmp) == -1)
00917       perror(definition_file_tmp);
00918 
00919     return ER_CORRUPT_TABLE_DEFINITION;
00920   }
00921 
00922   delete output;
00923 
00924   if (close(fd) == -1)
00925   {
00926     int error= errno;
00927     perror(definition_file_tmp);
00928 
00929     if (unlink(definition_file_tmp))
00930       perror(definition_file_tmp);
00931 
00932     return error;
00933   }
00934 
00935   if (rename(definition_file_tmp, file_name.c_str()) == -1)
00936   {
00937     int error= errno;
00938     perror(definition_file_tmp);
00939 
00940     if (unlink(definition_file_tmp))
00941       perror(definition_file_tmp);
00942 
00943     return error;
00944   }
00945 
00946   return 0;
00947 }
00948 
00952 bool StorageEngine::canCreateTable(const identifier::Table &identifier)
00953 {
00954   BOOST_FOREACH(EngineVector::reference it, g_engines)
00955   {
00956     if (not it->doCanCreateTable(identifier))
00957       return false;
00958   }
00959   return true;
00960 }
00961 
00962 bool StorageEngine::readTableFile(const std::string &path, message::Table &table_message)
00963 {
00964   std::fstream input(path.c_str(), std::ios::in | std::ios::binary);
00965 
00966   if (input.good())
00967   {
00968     try {
00969       if (table_message.ParseFromIstream(&input))
00970       {
00971         return true;
00972       }
00973     }
00974     catch (...)
00975     {
00976       my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
00977                table_message.name().empty() ? path.c_str() : table_message.name().c_str(),
00978                table_message.InitializationErrorString().empty() ? "": table_message.InitializationErrorString().c_str());
00979     }
00980   }
00981   else
00982   {
00983     perror(path.c_str());
00984   }
00985 
00986   return false;
00987 }
00988 
00989 std::ostream& operator<<(std::ostream& output, const StorageEngine &engine)
00990 {
00991   return output << "StorageEngine:(" <<  engine.getName() << ")";
00992 }
00993 
00994 } /* namespace plugin */
00995 } /* namespace drizzled */