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/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;
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(),
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;
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;
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())
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
00426
00427
00428 my_error(ER_CORRUPT_TABLE_DEFINITION_UNKNOWN, identifier);
00429
00430 return false;
00431 }
00432 else
00433 {
00434
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
00515
00516
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
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
00563
00564
00565
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
00646 char key[MAX_KEY_LENGTH];
00647 String str(key,sizeof(key),system_charset_info);
00648
00649
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
00771
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
00814 char key[MAX_KEY_LENGTH];
00815 String str(key,sizeof(key),system_charset_info);
00816
00817 if (key_nr == MAX_KEY)
00818 {
00819
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
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 }
00995 }