32 #include <google/protobuf/io/zero_copy_stream.h>
33 #include <google/protobuf/io/zero_copy_stream_impl.h>
37 #include <drizzled/base.h>
38 #include <drizzled/cursor.h>
39 #include <drizzled/plugin/storage_engine.h>
40 #include <drizzled/session.h>
41 #include <drizzled/error.h>
42 #include <drizzled/gettext.h>
43 #include <drizzled/data_home.h>
44 #include <drizzled/errmsg_print.h>
45 #include <drizzled/xid.h>
47 #include <drizzled/charset.h>
48 #include <drizzled/internal/my_sys.h>
49 #include <drizzled/table_proto.h>
50 #include <drizzled/plugin/event_observer.h>
51 #include <drizzled/table/shell.h>
52 #include <drizzled/message/cache.h>
53 #include <drizzled/key.h>
54 #include <drizzled/session/transactions.h>
55 #include <drizzled/open_tables_state.h>
57 #include <boost/algorithm/string/compare.hpp>
59 static bool shutdown_has_begun=
false;
64 static EngineVector g_engines;
65 static EngineVector g_schema_engines;
67 const std::string DEFAULT_STRING(
"default");
68 const std::string UNKNOWN_STRING(
"UNKNOWN");
69 const std::string DEFAULT_DEFINITION_FILE_EXT(
".dfe");
71 static std::set<std::string> set_of_table_definition_ext;
73 EngineVector &StorageEngine::getSchemaEngines()
75 return g_schema_engines;
78 StorageEngine::StorageEngine(
const std::string &name_arg,
79 const std::bitset<HTON_BIT_SIZE> &flags_arg) :
80 Plugin(name_arg,
"StorageEngine"),
81 MonitoredInTransaction(),
86 StorageEngine::~StorageEngine()
90 void StorageEngine::setTransactionReadWrite(Session& session)
92 TransactionContext &statement_ctx= session.transaction.stmt;
93 statement_ctx.markModifiedNonTransData();
96 int StorageEngine::renameTable(Session &session,
const identifier::Table &from,
const identifier::Table &to)
98 setTransactionReadWrite(session);
99 if (unlikely(plugin::EventObserver::beforeRenameTable(session, from, to)))
100 return ER_EVENT_OBSERVER_PLUGIN;
101 int error= doRenameTable(session, from, to);
102 if (unlikely(plugin::EventObserver::afterRenameTable(session, from, to, error)))
103 error= ER_EVENT_OBSERVER_PLUGIN;
125 int enoent_or_zero= ENOENT;
126 char buff[FN_REFLEN];
128 for (
const char **ext=
bas_ext(); *ext ; ext++)
130 internal::fn_format(buff, identifier.getPath().c_str(),
"", *ext,
131 MY_UNPACK_FILENAME|MY_APPEND_EXT);
132 if (internal::my_delete_with_symlink(buff, MYF(0)))
134 if ((error= errno) != ENOENT)
142 error= enoent_or_zero;
149 g_engines.push_back(engine);
151 if (engine->getTableDefinitionFileExtension().length())
153 assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
154 set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
157 if (engine->check_flag(HTON_BIT_SCHEMA_DICTIONARY))
158 g_schema_engines.push_back(engine);
163 void StorageEngine::removePlugin(StorageEngine *)
165 if (shutdown_has_begun)
167 shutdown_has_begun=
true;
169 g_schema_engines.clear();
172 StorageEngine *StorageEngine::findByName(
const std::string &predicate)
174 BOOST_FOREACH(EngineVector::reference it, g_engines)
176 if (not boost::iequals(it->getName(), predicate))
178 if (it->is_user_selectable())
185 StorageEngine *StorageEngine::findByName(Session& session,
const std::string &predicate)
187 if (boost::iequals(predicate, DEFAULT_STRING))
188 return session.getDefaultStorageEngine();
189 return findByName(predicate);
198 BOOST_FOREACH(EngineVector::reference it, g_engines)
200 if (*session.getEngineData(it))
201 it->close_connection(&session);
209 if (std::find_if(g_engines.begin(), g_engines.end(), std::mem_fun(&StorageEngine::flush_logs))
210 != g_engines.begin())
213 else if (engine->flush_logs())
223 drizzled::error_t &err;
229 drizzled::error_t &err_arg) :
230 session(session_arg),
231 identifier(identifier_arg),
232 table_message(table_message_arg),
235 result_type operator() (argument_type engine)
237 int ret= engine->doGetTableDefinition(session, identifier, table_message);
240 err=
static_cast<drizzled::error_t
>(ret);
242 return err ==
static_cast<drizzled::error_t
>(EEXIST) or err != static_cast<drizzled::error_t>(ENOENT);
251 bool include_temporary_tables)
253 if (include_temporary_tables && session.open_tables.doDoesTableExist(identifier))
255 BOOST_FOREACH(EngineVector::reference it, g_engines)
257 if (it->doDoesTableExist(session, identifier))
265 std::cerr <<
" Engine was called for doDoesTableExist() and does not implement it: " << getName() <<
"\n";
270 message::table::shared_ptr StorageEngine::getTableMessage(
Session& session,
272 bool include_temporary_tables)
274 drizzled::error_t error=
static_cast<drizzled::error_t
>(ENOENT);
275 if (include_temporary_tables)
277 if (
Table *table= session.open_tables.find_temporary_table(identifier))
279 return message::table::shared_ptr(
new message::Table(*table->getShare()->getTableMessage()));
283 drizzled::message::table::shared_ptr table_ptr;
284 if ((table_ptr= drizzled::message::Cache::singleton().find(identifier)))
289 message::Table message;
290 EngineVector::iterator iter= std::find_if(g_engines.begin(), g_engines.end(),
291 StorageEngineGetTableDefinition(session, identifier, message, error));
293 if (iter == g_engines.end())
295 return message::table::shared_ptr();
297 message::table::shared_ptr table_message(
new message::Table(message));
299 drizzled::message::Cache::singleton().insert(identifier, table_message);
301 return table_message;
308 drizzled::error_t &error;
314 drizzled::error_t &error_arg) :
315 session(session_arg),
316 identifier(identifier_arg),
320 result_type operator() (argument_type engine)
322 if (not engine->doDoesTableExist(session, identifier))
325 int local_error= engine->doDropTable(session, identifier);
333 case HA_ERR_NO_SUCH_TABLE:
335 error=
static_cast<drizzled::error_t
>(HA_ERR_NO_SUCH_TABLE);
339 error=
static_cast<drizzled::error_t
>(local_error);
346 bool StorageEngine::dropTable(
Session& session,
348 drizzled::error_t &error)
352 EngineVector::const_iterator iter= std::find_if(g_engines.begin(), g_engines.end(),
359 else if (iter == g_engines.end())
361 error= ER_BAD_TABLE_ERROR;
365 drizzled::message::Cache::singleton().erase(identifier);
370 bool StorageEngine::dropTable(Session& session,
371 const identifier::Table &identifier)
373 drizzled::error_t error;
374 return dropTable(session, identifier, error);
377 bool StorageEngine::dropTable(Session& session,
378 StorageEngine &engine,
379 const identifier::Table& identifier,
380 drizzled::error_t &error)
383 engine.setTransactionReadWrite(session);
385 assert(identifier.isTmp());
387 if (unlikely(plugin::EventObserver::beforeDropTable(session, identifier)))
389 error= ER_EVENT_OBSERVER_PLUGIN;
393 error=
static_cast<drizzled::error_t
>(engine.doDropTable(session, identifier));
395 if (unlikely(plugin::EventObserver::afterDropTable(session, identifier, error)))
397 error= ER_EVENT_OBSERVER_PLUGIN;
400 drizzled::message::Cache::singleton().erase(identifier);
417 drizzled::error_t error= EE_OK;
423 if (share.parse_table_proto(session, table_message) || share.open_table_from_share(&session, identifier,
"", 0, 0, table))
428 my_error(ER_CORRUPT_TABLE_DEFINITION_UNKNOWN, identifier);
435 if (table_message.type() == message::Table::TEMPORARY &&
436 share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) ==
true)
438 error= HA_ERR_UNSUPPORTED;
440 else if (table_message.type() != message::Table::TEMPORARY &&
441 share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) ==
true)
443 error= HA_ERR_UNSUPPORTED;
447 share.storage_engine->setTransactionReadWrite(session);
449 error=
static_cast<drizzled::error_t
>(share.storage_engine->doCreateTable(session,
455 if (error == ER_TABLE_PERMISSION_DENIED)
456 my_error(ER_TABLE_PERMISSION_DENIED, identifier);
458 my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), identifier.getSQLPath().c_str(), error);
461 return(error == EE_OK);
469 void StorageEngine::getIdentifiers(
Session &session,
const identifier::Schema &schema_identifier, identifier::table::vector &set_of_identifiers)
471 CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
473 if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
476 else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
479 else if (directory.fail())
481 errno= directory.getError();
483 my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), schema_identifier.getSQLPath().c_str());
485 my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
489 BOOST_FOREACH(EngineVector::reference it, g_engines)
490 it->doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
492 session.open_tables.doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
503 session(session_arg),
507 result_type operator() (argument_type identifier)
509 return engine->
doDropTable(session, identifier) == 0;
518 void StorageEngine::removeLostTemporaryTables(
Session &session,
const char *directory)
521 identifier::table::vector table_identifiers;
525 errno= dir.getError();
526 my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
531 CachedDirectory::Entries files= dir.getEntries();
533 for (CachedDirectory::Entries::iterator fileIter= files.begin();
534 fileIter != files.end(); fileIter++)
541 length= entry->filename.length();
542 entry->filename.resize(length - DEFAULT_DEFINITION_FILE_EXT.length());
546 path+= entry->filename;
548 if (StorageEngine::readTableFile(path, definition))
554 table_identifiers.push_back(identifier);
558 BOOST_FOREACH(EngineVector::reference it, g_engines)
560 table_identifiers.erase(std::remove_if(table_identifiers.begin(), table_identifiers.end(), DropTable(session, it)),
561 table_identifiers.end());
570 std::set<std::string> all_exts= set_of_table_definition_ext;
572 for (EngineVector::iterator iter= g_engines.begin();
573 iter != g_engines.end() ; iter++)
575 for (
const char **ext= (*iter)->bas_ext(); *ext ; ext++)
576 all_exts.insert(*ext);
579 CachedDirectory rescan(directory, all_exts);
581 files= rescan.getEntries();
582 for (CachedDirectory::Entries::iterator fileIter= files.begin();
583 fileIter != files.end(); fileIter++)
586 CachedDirectory::Entry *entry= *fileIter;
590 path+= entry->filename;
592 unlink(path.c_str());
608 drizzled::error_t textno= ER_GET_ERRNO;
611 textno=ER_OPEN_AS_READONLY;
617 textno=ER_FILE_NOT_FOUND;
619 case HA_ERR_KEY_NOT_FOUND:
620 case HA_ERR_NO_ACTIVE_RECORD:
621 case HA_ERR_END_OF_FILE:
622 textno=ER_KEY_NOT_FOUND;
624 case HA_ERR_WRONG_MRG_TABLE_DEF:
625 textno=ER_WRONG_MRG_TABLE;
627 case HA_ERR_FOUND_DUPP_KEY:
630 if ((
int) key_nr >= 0)
632 const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
634 print_keydup_error(key_nr, err_msg, table);
641 case HA_ERR_FOREIGN_DUPLICATE_KEY:
644 if ((
int) key_nr >= 0)
649 char key[MAX_KEY_LENGTH];
650 String str(key,
sizeof(key),system_charset_info);
653 key_unpack(&str, &table,(uint32_t) key_nr);
654 max_length= (DRIZZLE_ERRMSG_SIZE-
655 (uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
656 if (str.length() >= max_length)
658 str.length(max_length-4);
659 str.append(STRING_WITH_LEN(
"..."));
661 my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table.getShare()->getTableName(),
662 str.c_ptr(), key_nr+1);
668 case HA_ERR_FOUND_DUPP_UNIQUE:
669 textno=ER_DUP_UNIQUE;
671 case HA_ERR_RECORD_CHANGED:
675 textno=ER_NOT_KEYFILE;
677 case HA_ERR_WRONG_IN_RECORD:
678 textno= ER_CRASHED_ON_USAGE;
680 case HA_ERR_CRASHED_ON_USAGE:
681 textno=ER_CRASHED_ON_USAGE;
683 case HA_ERR_NOT_A_TABLE:
684 textno=
static_cast<drizzled::error_t
>(error);
686 case HA_ERR_CRASHED_ON_REPAIR:
687 textno=ER_CRASHED_ON_REPAIR;
689 case HA_ERR_OUT_OF_MEM:
690 textno=ER_OUT_OF_RESOURCES;
692 case HA_ERR_WRONG_COMMAND:
693 textno=ER_ILLEGAL_HA;
695 case HA_ERR_OLD_FILE:
696 textno=ER_OLD_KEYFILE;
698 case HA_ERR_UNSUPPORTED:
699 textno=ER_UNSUPPORTED_EXTENSION;
701 case HA_ERR_RECORD_FILE_FULL:
702 case HA_ERR_INDEX_FILE_FULL:
703 textno=ER_RECORD_FILE_FULL;
705 case HA_ERR_LOCK_WAIT_TIMEOUT:
706 textno=ER_LOCK_WAIT_TIMEOUT;
708 case HA_ERR_LOCK_TABLE_FULL:
709 textno=ER_LOCK_TABLE_FULL;
711 case HA_ERR_LOCK_DEADLOCK:
712 textno=ER_LOCK_DEADLOCK;
714 case HA_ERR_READ_ONLY_TRANSACTION:
715 textno=ER_READ_ONLY_TRANSACTION;
717 case HA_ERR_CANNOT_ADD_FOREIGN:
718 textno=ER_CANNOT_ADD_FOREIGN;
720 case HA_ERR_ROW_IS_REFERENCED:
724 my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_str());
727 case HA_ERR_NO_REFERENCED_ROW:
731 my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_str());
734 case HA_ERR_TABLE_DEF_CHANGED:
735 textno=ER_TABLE_DEF_CHANGED;
737 case HA_ERR_NO_SUCH_TABLE:
739 my_error(ER_TABLE_UNKNOWN, table.getShare()->getTableIdentifier());
742 case HA_ERR_LOG_ROW_FOR_REPLICATION_FAILED:
743 textno= ER_LOG_ROW_FOR_REPLICATION_FAILED;
745 case HA_ERR_DROP_INDEX_FK:
747 const char *ptr=
"???";
749 if ((
int) key_nr >= 0)
751 my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
754 case HA_ERR_TABLE_NEEDS_UPGRADE:
755 textno=ER_TABLE_NEEDS_UPGRADE;
757 case HA_ERR_TABLE_READONLY:
758 textno= ER_OPEN_AS_READONLY;
760 case HA_ERR_AUTOINC_READ_FAILED:
761 textno= ER_AUTOINC_READ_FAILED;
763 case HA_ERR_AUTOINC_ERANGE:
764 textno= ER_WARN_DATA_OUT_OF_RANGE;
766 case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
767 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
775 bool temporary=
false;
780 const char* engine_name= getName().c_str();
782 my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(), engine_name);
784 my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
788 my_error(ER_GET_ERRNO,errflag,error);
794 my_error(textno, errflag, table.getShare()->getTableName(), error);
813 void StorageEngine::print_keydup_error(uint32_t key_nr,
const char *msg,
const Table &table)
const
816 char key[MAX_KEY_LENGTH];
817 String str(key,
sizeof(key),system_charset_info);
819 if (key_nr == MAX_KEY)
822 str.copy(
"", 0, system_charset_info);
823 my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(),
"*UNKNOWN*");
828 key_unpack(&str, &table, (uint32_t) key_nr);
829 uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
830 if (str.length() >= max_length)
832 str.length(max_length-4);
833 str.append(STRING_WITH_LEN(
"..."));
835 my_printf_error(ER_DUP_ENTRY, msg,
836 MYF(0), str.c_ptr(), table.
key_info[key_nr].name);
841 int StorageEngine::deleteDefinitionFromPath(
const identifier::Table &identifier)
843 std::string path(identifier.getPath());
845 path.append(DEFAULT_DEFINITION_FILE_EXT);
847 return internal::my_delete(path.c_str(), MYF(0));
850 int StorageEngine::renameDefinitionFromPath(
const identifier::Table &dest,
const identifier::Table &src)
852 message::Table table_message;
853 std::string src_path(src.getPath());
854 std::string dest_path(dest.getPath());
856 src_path.append(DEFAULT_DEFINITION_FILE_EXT);
857 dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
859 bool was_read= StorageEngine::readTableFile(src_path.c_str(), table_message);
866 dest.copyToTableMessage(table_message);
868 int error= StorageEngine::writeDefinitionFromPath(dest, table_message);
872 if (unlink(src_path.c_str()))
873 perror(src_path.c_str());
879 int StorageEngine::writeDefinitionFromPath(
const identifier::Table &identifier,
const message::Table &table_message)
881 char definition_file_tmp[FN_REFLEN];
882 std::string file_name(identifier.getPath());
884 file_name.append(DEFAULT_DEFINITION_FILE_EXT);
886 snprintf(definition_file_tmp,
sizeof(definition_file_tmp),
"%sXXXXXX", file_name.c_str());
888 int fd= mkstemp(definition_file_tmp);
892 perror(definition_file_tmp);
896 google::protobuf::io::ZeroCopyOutputStream* output=
897 new google::protobuf::io::FileOutputStream(fd);
903 success= table_message.SerializeToZeroCopyStream(output);
912 my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), identifier.getSQLPath().c_str(), table_message.InitializationErrorString().c_str());
916 perror(definition_file_tmp);
918 if (unlink(definition_file_tmp) == -1)
919 perror(definition_file_tmp);
921 return ER_CORRUPT_TABLE_DEFINITION;
929 perror(definition_file_tmp);
931 if (unlink(definition_file_tmp))
932 perror(definition_file_tmp);
937 if (rename(definition_file_tmp, file_name.c_str()) == -1)
940 perror(definition_file_tmp);
942 if (unlink(definition_file_tmp))
943 perror(definition_file_tmp);
956 BOOST_FOREACH(EngineVector::reference it, g_engines)
958 if (not it->doCanCreateTable(identifier))
964 bool StorageEngine::readTableFile(
const std::string &path,
message::Table &table_message)
966 std::fstream input(path.c_str(), std::ios::in | std::ios::binary);
971 if (table_message.ParseFromIstream(&input))
978 my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
979 table_message.name().empty() ? path.c_str() : table_message.name().c_str(),
980 table_message.InitializationErrorString().empty() ?
"": table_message.InitializationErrorString().c_str());
985 perror(path.c_str());
991 std::ostream& operator<<(std::ostream& output,
const StorageEngine &engine)
993 return output <<
"StorageEngine:(" << engine.getName() <<
")";
virtual void print_error(int error, myf errflag, const Table &table) const
virtual bool get_error_message(int error, String *buf) const
static bool createTable(Session &session, const identifier::Table &identifier, message::Table &table_message)
int delete_table(bool free_share=false)
static bool canCreateTable(const drizzled::identifier::Table &identifier)
Defines the interface to the CachedDirectory class.
uint32_t get_dup_key(int error) const
virtual const char ** bas_ext() const =0
virtual int doDropTable(Session &session, const drizzled::identifier::Table &identifier)=0
static bool doesTableExist(Session &session, const drizzled::identifier::Table &identifier, bool include_temporary_tables=true)
static void closeConnection(Session &)