00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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;
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(),
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;
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;
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
00248
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
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
00564
00565
00566 my_error(ER_CORRUPT_TABLE_DEFINITION_UNKNOWN, identifier);
00567
00568 return false;
00569 }
00570 else
00571 {
00572
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
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
00706
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
00716
00717
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
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
00761
00762
00763
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
00844 char key[MAX_KEY_LENGTH];
00845 String str(key,sizeof(key),system_charset_info);
00846
00847
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
00970
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
01014 char key[MAX_KEY_LENGTH];
01015 String str(key,sizeof(key),system_charset_info);
01016
01017 if (key_nr == MAX_KEY)
01018 {
01019
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
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 }
01224 }