47
47
#include "drizzled/xid.h"
48
48
#include "drizzled/sql_table.h"
49
49
#include "drizzled/global_charset_info.h"
50
#include "drizzled/charset.h"
51
50
#include "drizzled/internal/my_sys.h"
52
#include "drizzled/db.h"
54
53
#include <drizzled/table_proto.h>
55
#include <drizzled/plugin/event_observer.h>
57
#include <drizzled/table/shell.h>
59
#include "drizzled/message/cache.h"
61
#include <boost/algorithm/string/compare.hpp>
55
#include "drizzled/hash.h"
63
57
static bool shutdown_has_begun= false; // Once we put in the container for the vector/etc for engines this will go away.
64
typedef hash_map<std::string, plugin::StorageEngine *> EngineMap;
65
typedef std::vector<plugin::StorageEngine *> EngineVector;
71
67
static EngineVector vector_of_engines;
72
static EngineVector vector_of_schema_engines;
68
static EngineVector vector_of_transactional_engines;
74
const std::string DEFAULT_STRING("default");
75
const std::string UNKNOWN_STRING("UNKNOWN");
76
const std::string DEFAULT_DEFINITION_FILE_EXT(".dfe");
70
const std::string plugin::UNKNOWN_STRING("UNKNOWN");
71
const std::string plugin::DEFAULT_DEFINITION_FILE_EXT(".dfe");
78
73
static std::set<std::string> set_of_table_definition_ext;
80
EngineVector &StorageEngine::getSchemaEngines()
82
return vector_of_schema_engines;
85
StorageEngine::StorageEngine(const std::string name_arg,
86
const std::bitset<HTON_BIT_SIZE> &flags_arg) :
87
Plugin(name_arg, "StorageEngine"),
88
MonitoredInTransaction(), /* This gives the storage engine a "slot" or ID */
93
StorageEngine::~StorageEngine()
97
void StorageEngine::setTransactionReadWrite(Session& session)
99
TransactionContext &statement_ctx= session.transaction.stmt;
100
statement_ctx.markModifiedNonTransData();
104
int StorageEngine::renameTable(Session &session, const TableIdentifier &from, const TableIdentifier &to)
107
setTransactionReadWrite(session);
109
if (unlikely(plugin::EventObserver::beforeRenameTable(session, from, to)))
111
error= ER_EVENT_OBSERVER_PLUGIN;
115
error = doRenameTable(session, from, to);
116
if (unlikely(plugin::EventObserver::afterRenameTable(session, from, to, error)))
75
plugin::StorageEngine::StorageEngine(const string name_arg,
76
const bitset<HTON_BIT_SIZE> &flags_arg,
78
: Plugin(name_arg, "StorageEngine"),
79
two_phase_commit(support_2pc),
90
pthread_mutex_init(&proto_cache_mutex, NULL);
94
plugin::StorageEngine::~StorageEngine()
96
pthread_mutex_destroy(&proto_cache_mutex);
99
void plugin::StorageEngine::setTransactionReadWrite(Session& session)
101
Ha_trx_info *ha_info= session.getEngineInfo(this);
104
When a storage engine method is called, the transaction must
105
have been started, unless it's a DDL call, for which the
106
storage engine starts the transaction internally, and commits
107
it internally, without registering in the ha_list.
108
Unfortunately here we can't know know for sure if the engine
109
has registered the transaction or not, so we must check.
111
if (ha_info->is_started())
114
* table_share can be NULL in plugin::StorageEngine::dropTable().
116
ha_info->set_trx_read_write();
122
int plugin::StorageEngine::doRenameTable(Session *,
127
for (const char **ext= bas_ext(); *ext ; ext++)
129
if (rename_file_ext(from, to, *ext))
118
error= ER_EVENT_OBSERVER_PLUGIN;
131
if ((error=errno) != ENOENT)
126
141
Delete all files with extension from bas_ext().
147
162
for (const char **ext= bas_ext(); *ext ; ext++)
149
internal::fn_format(buff, identifier.getPath().c_str(), "", *ext,
150
MY_UNPACK_FILENAME|MY_APPEND_EXT);
164
internal::fn_format(buff, table_path.c_str(), "", *ext,
165
MY_UNPACK_FILENAME|MY_APPEND_EXT);
151
166
if (internal::my_delete_with_symlink(buff, MYF(0)))
153
168
if ((error= errno) != ENOENT)
158
172
enoent_or_zero= 0; // No error for ENOENT
161
173
error= enoent_or_zero;
166
bool StorageEngine::addPlugin(StorageEngine *engine)
178
const char *plugin::StorageEngine::checkLowercaseNames(const char *path,
181
if (flags.test(HTON_BIT_FILE_BASED))
184
/* Ensure that table Cursor get path in lower case */
185
if (tmp_path != path)
186
strcpy(tmp_path, path);
189
we only should turn into lowercase database/table part
190
so start the process after homedirectory
192
if (strstr(tmp_path, drizzle_tmpdir) == tmp_path)
193
my_casedn_str(files_charset_info, tmp_path + strlen(drizzle_tmpdir));
195
my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
201
bool plugin::StorageEngine::addPlugin(plugin::StorageEngine *engine)
169
204
vector_of_engines.push_back(engine);
206
if (engine->check_flag(HTON_BIT_DOES_TRANSACTIONS))
207
vector_of_transactional_engines.push_back(engine);
171
209
if (engine->getTableDefinitionFileExtension().length())
173
211
assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
174
212
set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
177
if (engine->check_flag(HTON_BIT_SCHEMA_DICTIONARY))
178
vector_of_schema_engines.push_back(engine);
183
void StorageEngine::removePlugin(StorageEngine *)
218
void plugin::StorageEngine::removePlugin(plugin::StorageEngine *)
185
220
if (shutdown_has_begun == false)
187
222
vector_of_engines.clear();
188
vector_of_schema_engines.clear();
223
vector_of_transactional_engines.clear();
190
225
shutdown_has_begun= true;
194
229
class FindEngineByName
195
: public std::unary_function<StorageEngine *, bool>
230
: public unary_function<plugin::StorageEngine *, bool>
197
const std::string &predicate;
200
explicit FindEngineByName(const std::string &target_arg) :
201
predicate(target_arg)
234
explicit FindEngineByName(const string target_arg)
205
237
result_type operator() (argument_type engine)
207
return boost::iequals(engine->getName(), predicate);
239
string engine_name(engine->getName());
241
transform(engine_name.begin(), engine_name.end(),
242
engine_name.begin(), ::tolower);
243
return engine_name == target;
211
StorageEngine *StorageEngine::findByName(const std::string &predicate)
247
plugin::StorageEngine *plugin::StorageEngine::findByName(string find_str)
213
EngineVector::iterator iter= std::find_if(vector_of_engines.begin(),
214
vector_of_engines.end(),
215
FindEngineByName(predicate));
249
transform(find_str.begin(), find_str.end(),
250
find_str.begin(), ::tolower);
253
EngineVector::iterator iter= find_if(vector_of_engines.begin(),
254
vector_of_engines.end(),
255
FindEngineByName(find_str));
216
256
if (iter != vector_of_engines.end())
218
258
StorageEngine *engine= *iter;
262
308
don't bother to rollback here, it's done already
264
void StorageEngine::closeConnection(Session* session)
266
std::for_each(vector_of_engines.begin(), vector_of_engines.end(),
267
StorageEngineCloseConnection(session));
270
bool StorageEngine::flushLogs(StorageEngine *engine)
310
void plugin::StorageEngine::closeConnection(Session* session)
312
for_each(vector_of_engines.begin(), vector_of_engines.end(),
313
StorageEngineCloseConnection(session));
316
void plugin::StorageEngine::dropDatabase(char* path)
318
for_each(vector_of_engines.begin(), vector_of_engines.end(),
319
bind2nd(mem_fun(&plugin::StorageEngine::drop_database),path));
322
int plugin::StorageEngine::commitOrRollbackByXID(XID *xid, bool commit)
327
transform(vector_of_engines.begin(), vector_of_engines.end(), results.begin(),
328
bind2nd(mem_fun(&plugin::StorageEngine::commit_by_xid),xid));
330
transform(vector_of_engines.begin(), vector_of_engines.end(), results.begin(),
331
bind2nd(mem_fun(&plugin::StorageEngine::rollback_by_xid),xid));
333
if (find_if(results.begin(), results.end(), bind2nd(equal_to<int>(),0))
341
This function should be called when MySQL sends rows of a SELECT result set
342
or the EOF mark to the client. It releases a possible adaptive hash index
343
S-latch held by session in InnoDB and also releases a possible InnoDB query
344
FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
345
keep them over several calls of the InnoDB Cursor interface when a join
346
is executed. But when we let the control to pass to the client they have
347
to be released because if the application program uses mysql_use_result(),
348
it may deadlock on the S-latch if the application on another connection
349
performs another SQL query. In MySQL-4.1 this is even more important because
350
there a connection can have several SELECT queries open at the same time.
352
@param session the thread handle of the current connection
357
int plugin::StorageEngine::releaseTemporaryLatches(Session *session)
359
for_each(vector_of_transactional_engines.begin(), vector_of_transactional_engines.end(),
360
bind2nd(mem_fun(&plugin::StorageEngine::release_temporary_latches),session));
364
bool plugin::StorageEngine::flushLogs(plugin::StorageEngine *engine)
272
366
if (engine == NULL)
274
if (std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
275
std::mem_fun(&StorageEngine::flush_logs))
276
!= vector_of_engines.begin())
368
if (find_if(vector_of_engines.begin(), vector_of_engines.end(),
369
mem_fun(&plugin::StorageEngine::flush_logs))
370
!= vector_of_engines.begin())
281
if (engine->flush_logs())
375
if ((!engine->is_enabled()) ||
376
(engine->flush_logs()))
287
class StorageEngineGetTableDefinition: public std::unary_function<StorageEngine *,bool>
383
recover() step of xa.
386
there are three modes of operation:
387
- automatic recover after a crash
388
in this case commit_list != 0, tc_heuristic_recover==0
389
all xids from commit_list are committed, others are rolled back
390
- manual (heuristic) recover
391
in this case commit_list==0, tc_heuristic_recover != 0
392
DBA has explicitly specified that all prepared transactions should
393
be committed (or rolled back).
394
- no recovery (MySQL did not detect a crash)
395
in this case commit_list==0, tc_heuristic_recover == 0
396
there should be no prepared transactions in this case.
398
class XARecover : unary_function<plugin::StorageEngine *, void>
400
int trans_len, found_foreign_xids, found_my_xids;
406
XARecover(XID *trans_list_arg, int trans_len_arg,
407
HASH *commit_list_arg, bool dry_run_arg)
408
: trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
410
trans_list(trans_list_arg), commit_list(commit_list_arg),
416
return found_foreign_xids;
421
return found_my_xids;
424
result_type operator() (argument_type engine)
429
if (engine->is_enabled())
431
while ((got= engine->recover(trans_list, trans_len)) > 0 )
433
errmsg_printf(ERRMSG_LVL_INFO,
434
_("Found %d prepared transaction(s) in %s"),
435
got, engine->getName().c_str());
436
for (int i=0; i < got; i ++)
438
my_xid x=trans_list[i].get_my_xid();
439
if (!x) // not "mine" - that is generated by external TM
441
xid_cache_insert(trans_list+i, XA_PREPARED);
442
found_foreign_xids++;
452
hash_search(commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
453
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
455
engine->commit_by_xid(trans_list+i);
459
engine->rollback_by_xid(trans_list+i);
469
int plugin::StorageEngine::recover(HASH *commit_list)
471
XID *trans_list= NULL;
474
bool dry_run= (commit_list==0 && tc_heuristic_recover==0);
476
/* commit_list and tc_heuristic_recover cannot be set both */
477
assert(commit_list==0 || tc_heuristic_recover==0);
479
/* if either is set, total_ha_2pc must be set too */
480
if (total_ha_2pc <= 1)
484
#ifndef WILL_BE_DELETED_LATER
487
for now, only InnoDB supports 2pc. It means we can always safely
488
rollback all pending transactions, without risking inconsistent data
491
assert(total_ha_2pc == 2); // only InnoDB and binlog
492
tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
495
for (trans_len= MAX_XID_LIST_SIZE ;
496
trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
498
trans_list=(XID *)malloc(trans_len*sizeof(XID));
502
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
507
errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
510
XARecover recover_func(trans_list, trans_len, commit_list, dry_run);
511
for_each(vector_of_transactional_engines.begin(), vector_of_transactional_engines.end(),
515
if (recover_func.getForeignXIDs())
516
errmsg_printf(ERRMSG_LVL_WARN,
517
_("Found %d prepared XA transactions"),
518
recover_func.getForeignXIDs());
519
if (dry_run && recover_func.getMyXIDs())
521
errmsg_printf(ERRMSG_LVL_ERROR,
522
_("Found %d prepared transactions! It means that drizzled "
523
"was not shut down properly last time and critical "
524
"recovery information (last binlog or %s file) was "
525
"manually deleted after a crash. You have to start "
526
"drizzled with the --tc-heuristic-recover switch to "
527
"commit or rollback pending transactions."),
528
recover_func.getMyXIDs(), opt_tc_log_file);
532
errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
536
int plugin::StorageEngine::startConsistentSnapshot(Session *session)
538
for_each(vector_of_engines.begin(), vector_of_engines.end(),
539
bind2nd(mem_fun(&plugin::StorageEngine::start_consistent_snapshot),
544
class StorageEngineGetTableDefinition: public unary_function<plugin::StorageEngine *,bool>
289
546
Session& session;
290
const TableIdentifier &identifier;
291
message::Table &table_message;
549
const char *table_name;
551
message::Table *table_proto;
295
555
StorageEngineGetTableDefinition(Session& session_arg,
296
const TableIdentifier &identifier_arg,
297
message::Table &table_message_arg,
556
const char* path_arg,
558
const char *table_name_arg,
559
const bool is_tmp_arg,
560
message::Table *table_proto_arg,
299
562
session(session_arg),
300
identifier(identifier_arg),
301
table_message(table_message_arg),
565
table_name(table_name_arg),
567
table_proto(table_proto_arg),
304
570
result_type operator() (argument_type engine)
306
int ret= engine->doGetTableDefinition(session, identifier, table_message);
572
int ret= engine->doGetTableDefinition(session,
308
579
if (ret != ENOENT)
311
return err == EEXIST || err != ENOENT;
315
class StorageEngineDoesTableExist: public std::unary_function<StorageEngine *, bool>
318
const TableIdentifier &identifier;
321
StorageEngineDoesTableExist(Session& session_arg, const TableIdentifier &identifier_arg) :
322
session(session_arg),
323
identifier(identifier_arg)
326
result_type operator() (argument_type engine)
328
return engine->doDoesTableExist(session, identifier);
333
Utility method which hides some of the details of getTableDefinition()
335
bool plugin::StorageEngine::doesTableExist(Session &session,
336
const TableIdentifier &identifier,
337
bool include_temporary_tables)
339
if (include_temporary_tables)
341
if (session.doDoesTableExist(identifier))
345
EngineVector::iterator iter=
346
std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
347
StorageEngineDoesTableExist(session, identifier));
349
if (iter == vector_of_engines.end())
357
bool plugin::StorageEngine::doDoesTableExist(Session&, const drizzled::TableIdentifier&)
359
std::cerr << " Engine was called for doDoesTableExist() and does not implement it: " << this->getName() << "\n";
582
return *err == EEXIST;
586
static int drizzle_read_table_proto(const char* path, message::Table* table)
588
int fd= open(path, O_RDONLY);
593
google::protobuf::io::ZeroCopyInputStream* input=
594
new google::protobuf::io::FileInputStream(fd);
596
if (table->ParseFromZeroCopyStream(input) == false)
366
610
to ask engine if there are any new tables that should be written to disk
367
611
or any dropped tables that need to be removed from disk
369
int StorageEngine::getTableDefinition(Session& session,
370
const TableIdentifier &identifier,
371
message::table::shared_ptr &table_message,
372
bool include_temporary_tables)
613
int plugin::StorageEngine::getTableDefinition(Session& session,
614
TableIdentifier &identifier,
615
message::Table *table_proto)
617
return getTableDefinition(session,
618
identifier.getPath(), identifier.getDBName(), identifier.getTableName(), identifier.isTmp(),
622
int plugin::StorageEngine::getTableDefinition(Session& session,
627
message::Table *table_proto)
376
if (include_temporary_tables)
631
vector<plugin::StorageEngine *>::iterator iter=
632
find_if(vector_of_engines.begin(), vector_of_engines.end(),
633
StorageEngineGetTableDefinition(session, path, NULL, NULL, true, table_proto, &err));
635
if (iter == vector_of_engines.end())
378
Table *table= session.find_temporary_table(identifier);
637
string proto_path(path);
638
string file_ext(".dfe");
639
proto_path.append(file_ext);
641
int error= access(proto_path.c_str(), F_OK);
381
table_message.reset(new message::Table(*table->getShare()->getTableProto()));
650
int read_proto_err= drizzle_read_table_proto(proto_path.c_str(),
386
drizzled::message::table::shared_ptr table_ptr;
387
if ((table_ptr= drizzled::message::Cache::singleton().find(identifier)))
389
table_message= table_ptr;
392
message::Table message;
393
EngineVector::iterator iter=
394
std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
395
StorageEngineGetTableDefinition(session, identifier, message, err));
397
if (iter == vector_of_engines.end())
401
table_message.reset(new message::Table(message));
403
drizzled::message::Cache::singleton().insert(identifier, table_message);
439
693
returns ENOENT if the file doesn't exists.
441
int StorageEngine::dropTable(Session& session,
442
const TableIdentifier &identifier)
695
int plugin::StorageEngine::dropTable(Session& session,
696
TableIdentifier &identifier,
697
bool generate_warning)
446
message::table::shared_ptr src_proto;
447
StorageEngine *engine;
449
error_proto= StorageEngine::getTableDefinition(session, identifier, src_proto);
451
if (error_proto == ER_CORRUPT_TABLE_DEFINITION)
453
std::string error_message;
454
identifier.getSQLPath(error_message);
456
error_message.append(" : ");
457
error_message.append(src_proto->InitializationErrorString());
459
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), error_message.c_str());
461
return ER_CORRUPT_TABLE_DEFINITION;
465
engine= StorageEngine::findByName(session, src_proto->engine().name());
467
engine= StorageEngine::findByName(session, "");
471
std::string error_message;
472
identifier.getSQLPath(error_message);
473
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), error_message.c_str());
475
return ER_CORRUPT_TABLE_DEFINITION;
478
error= StorageEngine::dropTable(session, *engine, identifier);
701
message::Table src_proto;
702
plugin::StorageEngine* engine;
704
error_proto= plugin::StorageEngine::getTableDefinition(session,
708
engine= plugin::StorageEngine::findByName(session,
709
src_proto.engine().name());
713
engine->setTransactionReadWrite(session);
714
error= engine->doDropTable(session, identifier.getPath());
721
if (engine && engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY))
723
deleteDefinitionFromPath(identifier);
727
error= deleteDefinitionFromPath(identifier);
480
732
if (error_proto && error == 0)
486
int StorageEngine::dropTable(Session& session,
487
StorageEngine &engine,
488
const TableIdentifier &identifier)
492
engine.setTransactionReadWrite(session);
494
if (unlikely(plugin::EventObserver::beforeDropTable(session, identifier)))
496
error= ER_EVENT_OBSERVER_PLUGIN;
500
error= engine.doDropTable(session, identifier);
501
if (unlikely(plugin::EventObserver::afterDropTable(session, identifier, error)))
503
error= ER_EVENT_OBSERVER_PLUGIN;
507
drizzled::message::Cache::singleton().erase(identifier);
735
if (error && generate_warning)
738
Because engine->print_error() use my_error() to generate the error message
739
we use an internal error Cursor to intercept it and store the text
740
in a temporary buffer. Later the message will be presented to user
743
Ha_delete_table_error_handler ha_delete_table_error_handler;
745
session.push_internal_handler(&ha_delete_table_error_handler);
746
engine->print_error(error, 0);
748
session.pop_internal_handler();
751
XXX: should we convert *all* errors to warnings here?
752
What if the error is fatal?
754
push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
755
ha_delete_table_error_handler.buff);
514
762
Initiates table-file and calls appropriate database-creator.
769
@todo refactor to remove goto
521
int StorageEngine::createTable(Session &session,
522
const TableIdentifier &identifier,
523
message::Table& table_message)
771
int plugin::StorageEngine::createTable(Session& session,
772
TableIdentifier &identifier,
773
bool update_create_info,
774
message::Table& table_proto, bool proto_used)
526
TableShare share(identifier);
527
table::Shell table(share);
778
TableShare share(identifier.getDBName(), 0, identifier.getTableName(), identifier.getPath());
528
779
message::Table tmp_proto;
530
if (share.parse_table_proto(session, table_message) || share.open_table_from_share(&session, identifier, "", 0, 0, table))
532
// @note Error occured, we should probably do a little more here.
783
if (parse_table_proto(session, table_proto, &share))
536
/* Check for legal operations against the Engine using the proto (if used) */
537
if (table_message.type() == message::Table::TEMPORARY &&
788
if (open_table_def(session, &share))
792
if (open_table_from_share(&session, &share, "", 0, 0,
796
if (update_create_info)
797
table.updateCreateInfo(&table_proto);
799
/* Check for legal operations against the Engine using the proto (if used) */
802
if (table_proto.type() == message::Table::TEMPORARY &&
538
803
share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
540
805
error= HA_ERR_UNSUPPORTED;
542
else if (table_message.type() != message::Table::TEMPORARY &&
808
else if (table_proto.type() != message::Table::TEMPORARY &&
543
809
share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
545
811
error= HA_ERR_UNSUPPORTED;
549
share.storage_engine->setTransactionReadWrite(session);
551
error= share.storage_engine->doCreateTable(session,
560
identifier.getSQLPath(path);
561
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), path.c_str(), error);
564
table.delete_table();
816
if (! share.storage_engine->is_enabled())
818
error= HA_ERR_UNSUPPORTED;
824
char name_buff[FN_REFLEN];
825
const char *table_name_arg;
827
table_name_arg= share.storage_engine->checkLowercaseNames(identifier.getPath(), name_buff);
829
share.storage_engine->setTransactionReadWrite(session);
831
error= share.storage_engine->doCreateTable(&session,
838
table.closefrm(false);
842
char name_buff[FN_REFLEN];
843
sprintf(name_buff,"%s.%s", identifier.getDBName(), identifier.getTableName());
844
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
847
share.free_table_share();
567
848
return(error != 0);
570
Cursor *StorageEngine::getCursor(Table &arg)
575
class AddTableIdentifier :
576
public std::unary_function<StorageEngine *, void>
578
CachedDirectory &directory;
579
const SchemaIdentifier &identifier;
580
TableIdentifier::vector &set_of_identifiers;
851
Cursor *plugin::StorageEngine::getCursor(TableShare &share, memory::Root *alloc)
854
return create(share, alloc);
858
TODO -> Remove this to force all engines to implement their own file. Solves the "we only looked at dfe" problem.
860
void plugin::StorageEngine::doGetTableNames(CachedDirectory &directory, string&, set<string>& set_of_names)
862
CachedDirectory::Entries entries= directory.getEntries();
864
for (CachedDirectory::Entries::iterator entry_iter= entries.begin();
865
entry_iter != entries.end(); ++entry_iter)
867
CachedDirectory::Entry *entry= *entry_iter;
868
const string *filename= &entry->filename;
870
assert(filename->size());
872
const char *ext= strchr(filename->c_str(), '.');
874
if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_DEFINITION_FILE_EXT.c_str()) ||
875
(filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
879
char uname[NAME_LEN + 1];
880
uint32_t file_name_len;
882
file_name_len= filename_to_tablename(filename->c_str(), uname, sizeof(uname));
883
// TODO: Remove need for memory copy here
884
uname[file_name_len - sizeof(".dfe") + 1]= '\0'; // Subtract ending, place NULL
885
set_of_names.insert(uname);
891
public unary_function<plugin::StorageEngine *, void>
894
CachedDirectory& directory;
895
set<string>& set_of_names;
584
AddTableIdentifier(CachedDirectory &directory_arg, const SchemaIdentifier &identifier_arg, TableIdentifier::vector &of_names) :
899
AddTableName(CachedDirectory& directory_arg, string& database_name, set<string>& of_names) :
585
900
directory(directory_arg),
586
identifier(identifier_arg),
587
set_of_identifiers(of_names)
901
set_of_names(of_names)
591
906
result_type operator() (argument_type engine)
593
engine->doGetTableIdentifiers(directory, identifier, set_of_identifiers);
908
engine->doGetTableNames(directory, db, set_of_names);
598
void StorageEngine::getIdentifiers(Session &session, const SchemaIdentifier &schema_identifier, TableIdentifier::vector &set_of_identifiers)
912
void plugin::StorageEngine::getTableNames(string& db, set<string>& set_of_names)
600
static SchemaIdentifier INFORMATION_SCHEMA_IDENTIFIER("information_schema");
601
static SchemaIdentifier DATA_DICTIONARY_IDENTIFIER("data_dictionary");
603
CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
605
if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
607
else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
914
char tmp_path[FN_REFLEN];
916
build_table_filename(tmp_path, sizeof(tmp_path), db.c_str(), "", false);
918
CachedDirectory directory(tmp_path, set_of_table_definition_ext);
920
if (db.compare("information_schema"))
611
922
if (directory.fail())
613
924
errno= directory.getError();
614
925
if (errno == ENOENT)
617
schema_identifier.getSQLPath(path);
618
my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), path.c_str());
926
my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db.c_str());
622
928
my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
629
std::for_each(vector_of_engines.begin(), vector_of_engines.end(),
630
AddTableIdentifier(directory, schema_identifier, set_of_identifiers));
632
session.doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
933
for_each(vector_of_engines.begin(), vector_of_engines.end(),
934
AddTableName(directory, db, set_of_names));
635
class DropTable: public std::unary_function<TableIdentifier&, bool>
638
StorageEngine *engine;
642
DropTable(Session &session_arg, StorageEngine *engine_arg) :
643
session(session_arg),
647
result_type operator() (argument_type identifier)
649
return engine->doDropTable(session, identifier) == 0;
653
937
/* This will later be converted to TableIdentifiers */
654
class DropTables: public std::unary_function<StorageEngine *, void>
938
class DropTables: public unary_function<plugin::StorageEngine *, void>
656
940
Session &session;
657
TableIdentifier::vector &table_identifiers;
941
set<string>& set_of_names;
661
DropTables(Session &session_arg, TableIdentifier::vector &table_identifiers_arg) :
945
DropTables(Session &session_arg, set<string>& of_names) :
662
946
session(session_arg),
663
table_identifiers(table_identifiers_arg)
947
set_of_names(of_names)
666
950
result_type operator() (argument_type engine)
668
// True returning from DropTable means the table has been successfully
669
// deleted, so it should be removed from the list of tables to drop
670
table_identifiers.erase(std::remove_if(table_identifiers.begin(),
671
table_identifiers.end(),
672
DropTable(session, engine)),
673
table_identifiers.end());
953
for (set<string>::iterator iter= set_of_names.begin();
954
iter != set_of_names.end();
957
int error= engine->doDropTable(session, *iter);
959
// On a return of zero we know we found and deleted the table. So we
960
// remove it from our search.
962
set_of_names.erase(iter);
1008
int StorageEngine::deleteDefinitionFromPath(const TableIdentifier &identifier)
1300
int plugin::StorageEngine::deleteDefinitionFromPath(TableIdentifier &identifier)
1010
std::string path(identifier.getPath());
1302
string path(identifier.getPath());
1012
1304
path.append(DEFAULT_DEFINITION_FILE_EXT);
1014
1306
return internal::my_delete(path.c_str(), MYF(0));
1017
int StorageEngine::renameDefinitionFromPath(const TableIdentifier &dest, const TableIdentifier &src)
1309
int plugin::StorageEngine::renameDefinitionFromPath(TableIdentifier &dest, TableIdentifier &src)
1019
message::Table table_message;
1020
std::string src_path(src.getPath());
1021
std::string dest_path(dest.getPath());
1311
string src_path(src.getPath());
1312
string dest_path(dest.getPath());
1023
1314
src_path.append(DEFAULT_DEFINITION_FILE_EXT);
1024
1315
dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
1026
bool was_read= StorageEngine::readTableFile(src_path.c_str(), table_message);
1033
dest.copyToTableMessage(table_message);
1035
int error= StorageEngine::writeDefinitionFromPath(dest, table_message);
1039
if (unlink(src_path.c_str()))
1040
perror(src_path.c_str());
1317
return internal::my_rename(src_path.c_str(), dest_path.c_str(), MYF(MY_WME));
1046
int StorageEngine::writeDefinitionFromPath(const TableIdentifier &identifier, message::Table &table_message)
1320
int plugin::StorageEngine::writeDefinitionFromPath(TableIdentifier &identifier, message::Table &table_proto)
1048
char definition_file_tmp[FN_REFLEN];
1049
std::string file_name(identifier.getPath());
1322
string file_name(identifier.getPath());
1051
1324
file_name.append(DEFAULT_DEFINITION_FILE_EXT);
1053
snprintf(definition_file_tmp, sizeof(definition_file_tmp), "%sXXXXXX", file_name.c_str());
1055
int fd= mkstemp(definition_file_tmp);
1326
int fd= open(file_name.c_str(), O_RDWR|O_CREAT|O_TRUNC, internal::my_umask);
1059
perror(definition_file_tmp);
1063
1331
google::protobuf::io::ZeroCopyOutputStream* output=
1064
1332
new google::protobuf::io::FileOutputStream(fd);
1070
success= table_message.SerializeToZeroCopyStream(output);
1079
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1080
table_message.InitializationErrorString().c_str());
1334
if (table_proto.SerializeToZeroCopyStream(output) == false)
1083
if (close(fd) == -1)
1084
perror(definition_file_tmp);
1086
if (unlink(definition_file_tmp) == -1)
1087
perror(definition_file_tmp);
1089
return ER_CORRUPT_TABLE_DEFINITION;
1094
if (close(fd) == -1)
1097
perror(definition_file_tmp);
1099
if (unlink(definition_file_tmp))
1100
perror(definition_file_tmp);
1105
if (rename(definition_file_tmp, file_name.c_str()) == -1)
1108
perror(definition_file_tmp);
1110
if (unlink(definition_file_tmp))
1111
perror(definition_file_tmp);
1119
class CanCreateTable: public std::unary_function<StorageEngine *, bool>
1121
const TableIdentifier &identifier;
1124
CanCreateTable(const TableIdentifier &identifier_arg) :
1125
identifier(identifier_arg)
1128
result_type operator() (argument_type engine)
1130
return not engine->doCanCreateTable(identifier);
1136
@note on success table can be created.
1138
bool StorageEngine::canCreateTable(const TableIdentifier &identifier)
1140
EngineVector::iterator iter=
1141
std::find_if(vector_of_engines.begin(), vector_of_engines.end(),
1142
CanCreateTable(identifier));
1144
if (iter == vector_of_engines.end())
1152
bool StorageEngine::readTableFile(const std::string &path, message::Table &table_message)
1154
std::fstream input(path.c_str(), std::ios::in | std::ios::binary);
1159
if (table_message.ParseFromIstream(&input))
1166
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1167
table_message.InitializationErrorString().empty() ? "": table_message.InitializationErrorString().c_str());
1172
perror(path.c_str());
1180
} /* namespace plugin */
1181
1347
} /* namespace drizzled */