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))
551 table_identifiers.push_back(identifier);
555 BOOST_FOREACH(EngineVector::reference it, g_engines)
557 table_identifiers.erase(std::remove_if(table_identifiers.begin(), table_identifiers.end(), DropTable(session, it)),
558 table_identifiers.end());
567 std::set<std::string> all_exts= set_of_table_definition_ext;
569 for (EngineVector::iterator iter= g_engines.begin();
570 iter != g_engines.end() ; iter++)
572 for (
const char **ext= (*iter)->bas_ext(); *ext ; ext++)
573 all_exts.insert(*ext);
576 CachedDirectory rescan(directory, all_exts);
578 files= rescan.getEntries();
579 for (CachedDirectory::Entries::iterator fileIter= files.begin();
580 fileIter != files.end(); fileIter++)
583 CachedDirectory::Entry *entry= *fileIter;
587 path+= entry->filename;
589 unlink(path.c_str());
605 drizzled::error_t textno= ER_GET_ERRNO;
608 textno=ER_OPEN_AS_READONLY;
614 textno=ER_FILE_NOT_FOUND;
616 case HA_ERR_KEY_NOT_FOUND:
617 case HA_ERR_NO_ACTIVE_RECORD:
618 case HA_ERR_END_OF_FILE:
619 textno=ER_KEY_NOT_FOUND;
621 case HA_ERR_WRONG_MRG_TABLE_DEF:
622 textno=ER_WRONG_MRG_TABLE;
624 case HA_ERR_FOUND_DUPP_KEY:
627 if ((
int) key_nr >= 0)
629 const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
631 print_keydup_error(key_nr, err_msg, table);
638 case HA_ERR_FOREIGN_DUPLICATE_KEY:
641 if ((
int) key_nr >= 0)
646 char key[MAX_KEY_LENGTH];
647 String str(key,
sizeof(key),system_charset_info);
650 key_unpack(&str, &table,(uint32_t) key_nr);
651 max_length= (DRIZZLE_ERRMSG_SIZE-
652 (uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
653 if (str.length() >= max_length)
655 str.length(max_length-4);
656 str.append(STRING_WITH_LEN(
"..."));
658 my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table.getShare()->getTableName(),
659 str.c_ptr(), key_nr+1);
665 case HA_ERR_FOUND_DUPP_UNIQUE:
666 textno=ER_DUP_UNIQUE;
668 case HA_ERR_RECORD_CHANGED:
672 textno=ER_NOT_KEYFILE;
674 case HA_ERR_WRONG_IN_RECORD:
675 textno= ER_CRASHED_ON_USAGE;
677 case HA_ERR_CRASHED_ON_USAGE:
678 textno=ER_CRASHED_ON_USAGE;
680 case HA_ERR_NOT_A_TABLE:
681 textno=
static_cast<drizzled::error_t
>(error);
683 case HA_ERR_CRASHED_ON_REPAIR:
684 textno=ER_CRASHED_ON_REPAIR;
686 case HA_ERR_OUT_OF_MEM:
687 textno=ER_OUT_OF_RESOURCES;
689 case HA_ERR_WRONG_COMMAND:
690 textno=ER_ILLEGAL_HA;
692 case HA_ERR_OLD_FILE:
693 textno=ER_OLD_KEYFILE;
695 case HA_ERR_UNSUPPORTED:
696 textno=ER_UNSUPPORTED_EXTENSION;
698 case HA_ERR_RECORD_FILE_FULL:
699 case HA_ERR_INDEX_FILE_FULL:
700 textno=ER_RECORD_FILE_FULL;
702 case HA_ERR_LOCK_WAIT_TIMEOUT:
703 textno=ER_LOCK_WAIT_TIMEOUT;
705 case HA_ERR_LOCK_TABLE_FULL:
706 textno=ER_LOCK_TABLE_FULL;
708 case HA_ERR_LOCK_DEADLOCK:
709 textno=ER_LOCK_DEADLOCK;
711 case HA_ERR_READ_ONLY_TRANSACTION:
712 textno=ER_READ_ONLY_TRANSACTION;
714 case HA_ERR_CANNOT_ADD_FOREIGN:
715 textno=ER_CANNOT_ADD_FOREIGN;
717 case HA_ERR_ROW_IS_REFERENCED:
721 my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_str());
724 case HA_ERR_NO_REFERENCED_ROW:
728 my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_str());
731 case HA_ERR_TABLE_DEF_CHANGED:
732 textno=ER_TABLE_DEF_CHANGED;
734 case HA_ERR_NO_SUCH_TABLE:
736 identifier::Table identifier(table.getShare()->getSchemaName(), table.getShare()->getTableName());
737 my_error(ER_TABLE_UNKNOWN, identifier);
740 case HA_ERR_LOG_ROW_FOR_REPLICATION_FAILED:
741 textno= ER_LOG_ROW_FOR_REPLICATION_FAILED;
743 case HA_ERR_DROP_INDEX_FK:
745 const char *ptr=
"???";
747 if ((
int) key_nr >= 0)
749 my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
752 case HA_ERR_TABLE_NEEDS_UPGRADE:
753 textno=ER_TABLE_NEEDS_UPGRADE;
755 case HA_ERR_TABLE_READONLY:
756 textno= ER_OPEN_AS_READONLY;
758 case HA_ERR_AUTOINC_READ_FAILED:
759 textno= ER_AUTOINC_READ_FAILED;
761 case HA_ERR_AUTOINC_ERANGE:
762 textno= ER_WARN_DATA_OUT_OF_RANGE;
764 case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
765 my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
773 bool temporary=
false;
778 const char* engine_name= getName().c_str();
780 my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(), engine_name);
782 my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
786 my_error(ER_GET_ERRNO,errflag,error);
792 my_error(textno, errflag, table.getShare()->getTableName(), error);
811 void StorageEngine::print_keydup_error(uint32_t key_nr,
const char *msg,
const Table &table)
const
814 char key[MAX_KEY_LENGTH];
815 String str(key,
sizeof(key),system_charset_info);
817 if (key_nr == MAX_KEY)
820 str.copy(
"", 0, system_charset_info);
821 my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(),
"*UNKNOWN*");
826 key_unpack(&str, &table, (uint32_t) key_nr);
827 uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
828 if (str.length() >= max_length)
830 str.length(max_length-4);
831 str.append(STRING_WITH_LEN(
"..."));
833 my_printf_error(ER_DUP_ENTRY, msg,
834 MYF(0), str.c_ptr(), table.
key_info[key_nr].name);
839 int StorageEngine::deleteDefinitionFromPath(
const identifier::Table &identifier)
841 std::string path(identifier.getPath());
843 path.append(DEFAULT_DEFINITION_FILE_EXT);
845 return internal::my_delete(path.c_str(), MYF(0));
848 int StorageEngine::renameDefinitionFromPath(
const identifier::Table &dest,
const identifier::Table &src)
850 message::Table table_message;
851 std::string src_path(src.getPath());
852 std::string dest_path(dest.getPath());
854 src_path.append(DEFAULT_DEFINITION_FILE_EXT);
855 dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
857 bool was_read= StorageEngine::readTableFile(src_path.c_str(), table_message);
864 dest.copyToTableMessage(table_message);
866 int error= StorageEngine::writeDefinitionFromPath(dest, table_message);
870 if (unlink(src_path.c_str()))
871 perror(src_path.c_str());
877 int StorageEngine::writeDefinitionFromPath(
const identifier::Table &identifier,
const message::Table &table_message)
879 char definition_file_tmp[FN_REFLEN];
880 std::string file_name(identifier.getPath());
882 file_name.append(DEFAULT_DEFINITION_FILE_EXT);
884 snprintf(definition_file_tmp,
sizeof(definition_file_tmp),
"%sXXXXXX", file_name.c_str());
886 int fd= mkstemp(definition_file_tmp);
890 perror(definition_file_tmp);
894 google::protobuf::io::ZeroCopyOutputStream* output=
895 new google::protobuf::io::FileOutputStream(fd);
901 success= table_message.SerializeToZeroCopyStream(output);
910 my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), identifier.getSQLPath().c_str(), table_message.InitializationErrorString().c_str());
914 perror(definition_file_tmp);
916 if (unlink(definition_file_tmp) == -1)
917 perror(definition_file_tmp);
919 return ER_CORRUPT_TABLE_DEFINITION;
927 perror(definition_file_tmp);
929 if (unlink(definition_file_tmp))
930 perror(definition_file_tmp);
935 if (rename(definition_file_tmp, file_name.c_str()) == -1)
938 perror(definition_file_tmp);
940 if (unlink(definition_file_tmp))
941 perror(definition_file_tmp);
954 BOOST_FOREACH(EngineVector::reference it, g_engines)
956 if (not it->doCanCreateTable(identifier))
962 bool StorageEngine::readTableFile(
const std::string &path,
message::Table &table_message)
964 std::fstream input(path.c_str(), std::ios::in | std::ios::binary);
969 if (table_message.ParseFromIstream(&input))
976 my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
977 table_message.name().empty() ? path.c_str() : table_message.name().c_str(),
978 table_message.InitializationErrorString().empty() ?
"": table_message.InitializationErrorString().c_str());
983 perror(path.c_str());
989 std::ostream& operator<<(std::ostream& output,
const StorageEngine &engine)
991 return output <<
"StorageEngine:(" << engine.getName() <<
")";