31
32
#include "mysys/my_dir.h"
32
33
#include "mysys/hash.h"
34
#include "mysys/cached_directory.h"
34
36
#include <drizzled/definitions.h>
35
37
#include <drizzled/base.h>
36
#include <drizzled/handler.h>
38
#include <drizzled/cursor.h>
37
39
#include <drizzled/plugin/storage_engine.h>
38
40
#include <drizzled/session.h>
39
41
#include <drizzled/error.h>
40
42
#include <drizzled/gettext.h>
41
#include <drizzled/registry.h>
43
#include <drizzled/name_map.h>
42
44
#include <drizzled/unireg.h>
43
45
#include <drizzled/data_home.h>
44
46
#include "drizzled/errmsg_print.h"
45
#include <drizzled/plugin/registry.h>
47
#include "drizzled/name_map.h"
46
48
#include "drizzled/xid.h"
48
50
#include <drizzled/table_proto.h>
73
78
if (two_phase_commit)
81
pthread_mutex_init(&proto_cache_mutex, NULL);
79
85
plugin::StorageEngine::~StorageEngine()
81
87
savepoint_alloc_size-= orig_savepoint_offset;
88
pthread_mutex_destroy(&proto_cache_mutex);
84
void plugin::StorageEngine::setTransactionReadWrite(Session* session)
91
void plugin::StorageEngine::setTransactionReadWrite(Session& session)
86
Ha_trx_info *ha_info= &session->ha_data[getSlot()].ha_info[0];
93
Ha_trx_info *ha_info= &session.ha_data[getSlot()].ha_info[0];
88
95
When a storage engine method is called, the transaction must
89
96
have been started, unless it's a DDL call, for which the
190
197
_("Couldn't add StorageEngine"));
201
vector_of_engines.push_back(engine);
203
if (engine->check_flag(HTON_BIT_DOES_TRANSACTIONS))
204
vector_of_transactional_engines.push_back(engine);
206
if (engine->getTableDefinitionExt().length())
208
assert(engine->getTableDefinitionExt().length() == MAX_STORAGE_ENGINE_FILE_EXT);
209
set_of_table_definition_ext.insert(engine->getTableDefinitionExt());
196
215
void plugin::StorageEngine::removePlugin(plugin::StorageEngine *engine)
198
217
all_engines.remove(engine);
201
plugin::StorageEngine *plugin::StorageEngine::findByName(Session *session,
218
vector_of_engines.clear();
219
vector_of_transactional_engines.clear();
222
plugin::StorageEngine *plugin::StorageEngine::findByName(string find_str)
224
transform(find_str.begin(), find_str.end(),
225
find_str.begin(), ::tolower);
227
plugin::StorageEngine *engine= all_engines.find(find_str);
229
if (engine && engine->is_user_selectable())
235
plugin::StorageEngine *plugin::StorageEngine::findByName(Session& session,
205
239
transform(find_str.begin(), find_str.end(),
206
240
find_str.begin(), ::tolower);
207
string default_str("default");
208
if (find_str == default_str)
209
return ha_default_storage_engine(session);
242
if (find_str.compare("default") == 0)
243
return session.getDefaultStorageEngine();
211
245
plugin::StorageEngine *engine= all_engines.find(find_str);
241
275
void plugin::StorageEngine::closeConnection(Session* session)
243
for_each(all_engines.begin(), all_engines.end(),
277
for_each(vector_of_engines.begin(), vector_of_engines.end(),
244
278
StorageEngineCloseConnection(session));
247
281
void plugin::StorageEngine::dropDatabase(char* path)
249
for_each(all_engines.begin(), all_engines.end(),
283
for_each(vector_of_engines.begin(), vector_of_engines.end(),
250
284
bind2nd(mem_fun(&plugin::StorageEngine::drop_database),path));
466
501
int plugin::StorageEngine::startConsistentSnapshot(Session *session)
468
for_each(all_engines.begin(), all_engines.end(),
503
for_each(vector_of_engines.begin(), vector_of_engines.end(),
469
504
bind2nd(mem_fun(&plugin::StorageEngine::start_consistent_snapshot),
474
class StorageEngineGetTableProto: public unary_function<plugin::StorageEngine *,bool>
509
class StorageEngineGetTableDefinition: public unary_function<plugin::StorageEngine *,bool>
476
512
const char* path;
514
const char *table_name;
477
516
message::Table *table_proto;
480
StorageEngineGetTableProto(const char* path_arg,
481
message::Table *table_proto_arg,
483
:path(path_arg), table_proto(table_proto_arg), err(err_arg) {}
520
StorageEngineGetTableDefinition(Session& session_arg,
521
const char* path_arg,
523
const char *table_name_arg,
524
const bool is_tmp_arg,
525
message::Table *table_proto_arg,
527
session(session_arg),
530
table_name(table_name_arg),
532
table_proto(table_proto_arg),
485
535
result_type operator() (argument_type engine)
487
int ret= engine->getTableProtoImplementation(path, table_proto);
537
int ret= engine->doGetTableDefinition(session,
489
544
if (ret != ENOENT)
519
Call this function in order to give the handler the possiblity
574
Call this function in order to give the Cursor the possiblity
520
575
to ask engine if there are any new tables that should be written to disk
521
576
or any dropped tables that need to be removed from disk
523
int plugin::StorageEngine::getTableProto(const char* path,
524
message::Table *table_proto)
578
int plugin::StorageEngine::getTableDefinition(Session& session,
583
message::Table *table_proto)
528
::drizzled::Registry<plugin::StorageEngine *>::iterator iter=
529
find_if(all_engines.begin(), all_engines.end(),
530
StorageEngineGetTableProto(path, table_proto, &err));
531
if (iter == all_engines.end())
587
vector<plugin::StorageEngine *>::iterator iter=
588
find_if(vector_of_engines.begin(), vector_of_engines.end(),
589
StorageEngineGetTableDefinition(session, path, NULL, NULL, true, table_proto, &err));
591
if (iter == vector_of_engines.end())
533
593
string proto_path(path);
534
594
string file_ext(".dfe");
588
class DeleteTableStorageEngine
589
: public unary_function<plugin::StorageEngine *, void>
596
DeleteTableStorageEngine(Session *session_arg, const char *path_arg,
597
handler **file_arg, int *error_arg)
598
: session(session_arg), path(path_arg), file(file_arg), dt_error(error_arg) {}
600
result_type operator() (argument_type engine)
602
char tmp_path[FN_REFLEN];
605
if(*dt_error!=ENOENT) /* already deleted table */
611
if (!engine->is_enabled())
614
if ((tmp_file= engine->create(NULL, session->mem_root)))
619
path= engine->checkLowercaseNames(path, tmp_path);
620
const string table_path(path);
621
int tmp_error= engine->doDeleteTable(session, table_path);
623
if (tmp_error != ENOENT)
627
if (engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY))
628
delete_table_proto_file(path);
630
tmp_error= delete_table_proto_file(path);
633
*dt_error= tmp_error;
648
649
This should return ENOENT if the file doesn't exists.
649
650
The .frm file will be deleted only if we return 0 or ENOENT
651
int plugin::StorageEngine::deleteTable(Session *session, const char *path,
652
const char *db, const char *alias,
653
bool generate_warning)
652
int plugin::StorageEngine::dropTable(Session& session, const char *path,
653
const char *db, const char *alias,
654
bool generate_warning)
655
TableShare dummy_share;
657
memset(&dummy_table, 0, sizeof(dummy_table));
658
memset(&dummy_share, 0, sizeof(dummy_share));
660
dummy_table.s= &dummy_share;
665
for_each(all_engines.begin(), all_engines.end(),
666
DeleteTableStorageEngine(session, path, &file, &error));
668
if (error == ENOENT) /* proto may be left behind */
669
error= delete_table_proto_file(path);
658
message::Table src_proto;
659
plugin::StorageEngine* engine;
661
error_proto= plugin::StorageEngine::getTableDefinition(session,
668
engine= plugin::StorageEngine::findByName(session,
669
src_proto.engine().name());
673
engine->setTransactionReadWrite(session);
674
error= engine->doDropTable(session, path);
681
if (engine && engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY))
682
delete_table_proto_file(path);
684
error= delete_table_proto_file(path);
688
if (error_proto && error == 0)
671
691
if (error && generate_warning)
693
TableShare dummy_share;
699
if ((file= engine->create(NULL, session.mem_root)))
702
memset(&dummy_table, 0, sizeof(dummy_table));
703
memset(&dummy_share, 0, sizeof(dummy_share));
704
dummy_table.s= &dummy_share;
674
707
Because file->print_error() use my_error() to generate the error message
675
we use an internal error handler to intercept it and store the text
708
we use an internal error Cursor to intercept it and store the text
676
709
in a temporary buffer. Later the message will be presented to user
703
736
XXX: should we convert *all* errors to warnings here?
704
737
What if the error is fatal?
706
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
739
push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
707
740
ha_delete_table_error_handler.buff);
716
class DFETableNameIterator: public plugin::TableNameIteratorImplementation
720
uint32_t current_entry;
723
DFETableNameIterator(const string &database)
724
: plugin::TableNameIteratorImplementation(database),
729
~DFETableNameIterator();
731
int next(string *name);
735
DFETableNameIterator::~DFETableNameIterator()
741
int DFETableNameIterator::next(string *name)
743
char uname[NAME_LEN + 1];
746
uint32_t file_name_len;
747
const char *wild= NULL;
752
char path[FN_REFLEN];
754
build_table_filename(path, sizeof(path), db.c_str(), "", false);
756
dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0));
760
if (my_errno == ENOENT)
761
my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db.c_str());
763
my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
773
if (current_entry == dirp->number_off_files)
780
file= dirp->dir_entry + current_entry;
782
if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),".dfe") ||
783
is_prefix(file->name, TMP_FILE_PREFIX))
787
file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
789
uname[file_name_len]= '\0';
791
if (wild && wild_compare(uname, wild, 0))
802
plugin::TableNameIterator::TableNameIterator(const string &db)
803
: current_implementation(NULL), database(db)
805
engine_iter= all_engines.begin();
806
default_implementation= new DFETableNameIterator(database);
809
plugin::TableNameIterator::~TableNameIterator()
811
delete current_implementation;
812
if (current_implementation != default_implementation)
814
delete default_implementation;
818
int plugin::TableNameIterator::next(string *name)
823
if (current_implementation == NULL)
825
while(current_implementation == NULL &&
826
(engine_iter != all_engines.end()))
828
plugin::StorageEngine *engine= *engine_iter;
829
current_implementation= engine->tableNameIterator(database);
833
if (current_implementation == NULL &&
834
(engine_iter == all_engines.end()))
836
current_implementation= default_implementation;
840
err= current_implementation->next(name);
844
if (current_implementation != default_implementation)
846
delete current_implementation;
847
current_implementation= NULL;
857
747
Initiates table-file and calls appropriate database-creator.
864
int plugin::StorageEngine::createTable(Session *session, const char *path,
754
int plugin::StorageEngine::createTable(Session& session, const char *path,
865
755
const char *db, const char *table_name,
866
HA_CREATE_INFO *create_info,
756
HA_CREATE_INFO& create_info,
867
757
bool update_create_info,
868
drizzled::message::Table *table_proto)
758
drizzled::message::Table& table_proto, bool proto_used)
872
762
TableShare share(db, 0, table_name, path);
873
drizzled::message::Table tmp_proto;
763
message::Table tmp_proto;
877
if (parse_table_proto(session, *table_proto, &share))
767
if (parse_table_proto(session, table_proto, &share))
882
table_proto= &tmp_proto;
883
772
if (open_table_def(session, &share))
887
if (open_table_from_share(session, &share, "", 0, (uint32_t) READ_ALL, 0,
776
if (open_table_from_share(&session, &share, "", 0, (uint32_t) READ_ALL, 0,
888
777
&table, OTM_CREATE))
891
780
if (update_create_info)
892
table.updateCreateInfo(create_info, table_proto);
894
error= share.storage_engine->doCreateTable(session, path, &table,
895
create_info, table_proto);
781
table.updateCreateInfo(&create_info, &table_proto);
784
char name_buff[FN_REFLEN];
785
const char *table_name_arg;
787
table_name_arg= share.storage_engine->checkLowercaseNames(path, name_buff);
789
share.storage_engine->setTransactionReadWrite(session);
791
error= share.storage_engine->doCreateTable(&session, table_name_arg, table,
792
create_info, table_proto);
896
795
table.closefrm(false);
905
804
return(error != 0);
807
Cursor *plugin::StorageEngine::getCursor(TableShare *share, MEM_ROOT *alloc)
813
if ((file= create(share, alloc)))
819
TODO -> Remove this to force all engines to implement their own file. Solves the "we only looked at dfe" problem.
821
void plugin::StorageEngine::doGetTableNames(CachedDirectory &directory, string&, set<string>& set_of_names)
823
CachedDirectory::Entries entries= directory.getEntries();
825
for (CachedDirectory::Entries::iterator entry_iter= entries.begin();
826
entry_iter != entries.end(); ++entry_iter)
828
CachedDirectory::Entry *entry= *entry_iter;
829
string *filename= &entry->filename;
831
assert(filename->size());
833
const char *ext= strchr(filename->c_str(), '.');
835
if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_DEFINITION_FILE_EXT.c_str()) ||
836
is_prefix(filename->c_str(), TMP_FILE_PREFIX))
840
char uname[NAME_LEN + 1];
841
uint32_t file_name_len;
843
file_name_len= filename_to_tablename(filename->c_str(), uname, sizeof(uname));
844
// TODO: Remove need for memory copy here
845
uname[file_name_len - sizeof(".dfe") + 1]= '\0'; // Subtract ending, place NULL
846
set_of_names.insert(uname);
852
public unary_function<plugin::StorageEngine *, void>
855
CachedDirectory& directory;
856
set<string>& set_of_names;
860
AddTableName(CachedDirectory& directory_arg, string& database_name, set<string>& of_names) :
861
directory(directory_arg),
862
set_of_names(of_names)
867
result_type operator() (argument_type engine)
869
engine->doGetTableNames(directory, db, set_of_names);
873
void plugin::StorageEngine::getTableNames(string& db, set<string>& set_of_names)
875
char tmp_path[FN_REFLEN];
877
build_table_filename(tmp_path, sizeof(tmp_path), db.c_str(), "", false);
879
CachedDirectory directory(tmp_path, set_of_table_definition_ext);
881
if (db.compare("information_schema"))
883
if (directory.fail())
885
my_errno= directory.getError();
886
if (my_errno == ENOENT)
887
my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db.c_str());
889
my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), my_errno);
894
for_each(vector_of_engines.begin(), vector_of_engines.end(),
895
AddTableName(directory, db, set_of_names));
910
899
} /* namespace drizzled */
914
handler *get_new_handler(TableShare *share, MEM_ROOT *alloc,
915
drizzled::plugin::StorageEngine *engine)
919
if (engine && engine->is_enabled())
921
if ((file= engine->create(share, alloc)))
926
Try the default table type
927
Here the call to current_session() is ok as we call this function a lot of
928
times but we enter this branch very seldom.
930
return(get_new_handler(share, alloc, ha_default_storage_engine(current_session)));
935
Return the default storage engine plugin::StorageEngine for thread
937
@param ha_default_storage_engine(session)
938
@param session current thread
941
pointer to plugin::StorageEngine
943
drizzled::plugin::StorageEngine *ha_default_storage_engine(Session *session)
945
if (session->variables.storage_engine)
946
return session->variables.storage_engine;
947
return global_system_variables.storage_engine;