17
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
32
#include <google/protobuf/io/zero_copy_stream.h>
33
#include <google/protobuf/io/zero_copy_stream_impl.h>
35
#include "drizzled/cached_directory.h"
20
#include <drizzled/server_includes.h>
37
21
#include <drizzled/definitions.h>
38
22
#include <drizzled/base.h>
39
#include <drizzled/cursor.h>
23
#include <drizzled/handler.h>
40
24
#include <drizzled/plugin/storage_engine.h>
41
25
#include <drizzled/session.h>
42
26
#include <drizzled/error.h>
43
27
#include <drizzled/gettext.h>
28
#include <drizzled/registry.h>
44
29
#include <drizzled/unireg.h>
45
30
#include <drizzled/data_home.h>
46
#include "drizzled/errmsg_print.h"
47
#include "drizzled/xid.h"
48
#include "drizzled/sql_table.h"
49
#include "drizzled/global_charset_info.h"
50
#include "drizzled/charset.h"
51
#include "drizzled/internal/my_sys.h"
52
#include "drizzled/db.h"
54
#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>
63
static bool shutdown_has_begun= false; // Once we put in the container for the vector/etc for engines this will go away.
71
static EngineVector vector_of_engines;
72
static EngineVector vector_of_schema_engines;
74
const std::string DEFAULT_STRING("default");
75
const std::string UNKNOWN_STRING("UNKNOWN");
76
const std::string DEFAULT_DEFINITION_FILE_EXT(".dfe");
78
static std::set<std::string> set_of_table_definition_ext;
80
EngineVector &StorageEngine::getSchemaEngines()
82
return vector_of_schema_engines;
31
#include <drizzled/plugin_registry.h>
38
drizzled::Registry<StorageEngine *> all_engines;
40
void add_storage_engine(StorageEngine *engine)
42
all_engines.add(engine);
45
void remove_storage_engine(StorageEngine *engine)
47
all_engines.remove(engine);
85
50
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 */
51
const std::bitset<HTON_BIT_SIZE> &flags_arg,
52
size_t savepoint_offset_arg,
54
: name(name_arg), two_phase_commit(support_2pc), enabled(true),
56
savepoint_offset(savepoint_alloc_size),
57
orig_savepoint_offset(savepoint_offset_arg),
62
savepoint_alloc_size+= orig_savepoint_offset;
93
70
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)))
118
error= ER_EVENT_OBSERVER_PLUGIN;
72
savepoint_alloc_size-= orig_savepoint_offset;
76
/* args: current_session, db, name */
77
int StorageEngine::table_exists_in_engine(Session*, const char *, const char *)
79
return HA_ERR_NO_SUCH_TABLE;
82
void StorageEngine::setTransactionReadWrite(Session* session)
84
Ha_trx_info *ha_info= &session->ha_data[getSlot()].ha_info[0];
86
When a storage engine method is called, the transaction must
87
have been started, unless it's a DDL call, for which the
88
storage engine starts the transaction internally, and commits
89
it internally, without registering in the ha_list.
90
Unfortunately here we can't know know for sure if the engine
91
has registered the transaction or not, so we must check.
93
if (ha_info->is_started())
96
table_share can be NULL in ha_delete_table(). See implementation
97
of standalone function ha_delete_table() in sql_base.cc.
99
// if (table_share == NULL || table_share->tmp_table == NO_TMP_TABLE)
100
ha_info->set_trx_read_write();
106
Return the default storage engine StorageEngine for thread
108
@param ha_default_storage_engine(session)
109
@param session current thread
112
pointer to StorageEngine
114
StorageEngine *ha_default_storage_engine(Session *session)
116
if (session->variables.storage_engine)
117
return session->variables.storage_engine;
118
return global_system_variables.storage_engine;
123
Return the storage engine StorageEngine for the supplied name
125
@param session current thread
126
@param name name of storage engine
129
pointer to storage engine plugin handle
131
StorageEngine *ha_resolve_by_name(Session *session, const LEX_STRING *name)
134
string find_str(name->str, name->length);
135
transform(find_str.begin(), find_str.end(),
136
find_str.begin(), ::tolower);
137
string default_str("default");
138
if (find_str == default_str)
139
return ha_default_storage_engine(session);
142
StorageEngine *engine= all_engines.find(find_str);
144
if (engine && engine->is_user_selectable())
151
handler *get_new_handler(TableShare *share, MEM_ROOT *alloc,
152
StorageEngine *engine)
156
if (engine && engine->is_enabled())
158
if ((file= engine->create(share, alloc)))
163
Try the default table type
164
Here the call to current_session() is ok as we call this function a lot of
165
times but we enter this branch very seldom.
167
return(get_new_handler(share, alloc, ha_default_storage_engine(current_session)));
170
class StorageEngineCloseConnection
171
: public unary_function<StorageEngine *, void>
175
StorageEngineCloseConnection(Session *session_arg) : session(session_arg) {}
177
there's no need to rollback here as all transactions must
178
be rolled back already
180
inline result_type operator() (argument_type engine)
182
if (engine->is_enabled() &&
183
session_get_ha_data(session, engine))
184
engine->close_connection(session);
190
don't bother to rollback here, it's done already
192
void ha_close_connection(Session* session)
194
for_each(all_engines.begin(), all_engines.end(),
195
StorageEngineCloseConnection(session));
198
void ha_drop_database(char* path)
200
for_each(all_engines.begin(), all_engines.end(),
201
bind2nd(mem_fun(&StorageEngine::drop_database),path));
204
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
209
transform(all_engines.begin(), all_engines.end(), results.begin(),
210
bind2nd(mem_fun(&StorageEngine::commit_by_xid),xid));
212
transform(all_engines.begin(), all_engines.end(), results.begin(),
213
bind2nd(mem_fun(&StorageEngine::rollback_by_xid),xid));
215
if (find_if(results.begin(), results.end(), bind2nd(equal_to<int>(),0))
224
This function should be called when MySQL sends rows of a SELECT result set
225
or the EOF mark to the client. It releases a possible adaptive hash index
226
S-latch held by session in InnoDB and also releases a possible InnoDB query
227
FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
228
keep them over several calls of the InnoDB handler interface when a join
229
is executed. But when we let the control to pass to the client they have
230
to be released because if the application program uses mysql_use_result(),
231
it may deadlock on the S-latch if the application on another connection
232
performs another SQL query. In MySQL-4.1 this is even more important because
233
there a connection can have several SELECT queries open at the same time.
235
@param session the thread handle of the current connection
240
int ha_release_temporary_latches(Session *session)
242
for_each(all_engines.begin(), all_engines.end(),
243
bind2nd(mem_fun(&StorageEngine::release_temporary_latches),session));
248
bool ha_flush_logs(StorageEngine *engine)
252
if (find_if(all_engines.begin(), all_engines.end(),
253
mem_fun(&StorageEngine::flush_logs))
254
!= all_engines.begin())
259
if ((!engine->is_enabled()) ||
260
(engine->flush_logs()))
267
recover() step of xa.
270
there are three modes of operation:
271
- automatic recover after a crash
272
in this case commit_list != 0, tc_heuristic_recover==0
273
all xids from commit_list are committed, others are rolled back
274
- manual (heuristic) recover
275
in this case commit_list==0, tc_heuristic_recover != 0
276
DBA has explicitly specified that all prepared transactions should
277
be committed (or rolled back).
278
- no recovery (MySQL did not detect a crash)
279
in this case commit_list==0, tc_heuristic_recover == 0
280
there should be no prepared transactions in this case.
282
class XARecover : unary_function<StorageEngine *, void>
284
int trans_len, found_foreign_xids, found_my_xids;
290
XARecover(XID *trans_list_arg, int trans_len_arg,
291
HASH *commit_list_arg, bool dry_run_arg)
292
: trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
293
trans_list(trans_list_arg), commit_list(commit_list_arg),
299
return found_foreign_xids;
304
return found_my_xids;
307
result_type operator() (argument_type engine)
312
if (engine->is_enabled())
314
while ((got= engine->recover(trans_list, trans_len)) > 0 )
316
errmsg_printf(ERRMSG_LVL_INFO,
317
_("Found %d prepared transaction(s) in %s"),
318
got, engine->getName().c_str());
319
for (int i=0; i < got; i ++)
321
my_xid x=trans_list[i].get_my_xid();
322
if (!x) // not "mine" - that is generated by external TM
324
xid_cache_insert(trans_list+i, XA_PREPARED);
325
found_foreign_xids++;
335
hash_search(commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
336
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
338
engine->commit_by_xid(trans_list+i);
342
engine->rollback_by_xid(trans_list+i);
353
int ha_recover(HASH *commit_list)
355
XID *trans_list= NULL;
358
bool dry_run= (commit_list==0 && tc_heuristic_recover==0);
360
/* commit_list and tc_heuristic_recover cannot be set both */
361
assert(commit_list==0 || tc_heuristic_recover==0);
363
/* if either is set, total_ha_2pc must be set too */
364
if (total_ha_2pc <= 1)
368
#ifndef WILL_BE_DELETED_LATER
371
for now, only InnoDB supports 2pc. It means we can always safely
372
rollback all pending transactions, without risking inconsistent data
375
assert(total_ha_2pc == 2); // only InnoDB and binlog
376
tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
379
for (trans_len= MAX_XID_LIST_SIZE ;
380
trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
382
trans_list=(XID *)malloc(trans_len*sizeof(XID));
386
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
391
errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
394
XARecover recover_func(trans_list, trans_len, commit_list, dry_run);
395
for_each(all_engines.begin(), all_engines.end(), recover_func);
398
if (recover_func.getForeignXIDs())
399
errmsg_printf(ERRMSG_LVL_WARN,
400
_("Found %d prepared XA transactions"),
401
recover_func.getForeignXIDs());
402
if (dry_run && recover_func.getMyXIDs())
404
errmsg_printf(ERRMSG_LVL_ERROR,
405
_("Found %d prepared transactions! It means that drizzled "
406
"was not shut down properly last time and critical "
407
"recovery information (last binlog or %s file) was "
408
"manually deleted after a crash. You have to start "
409
"drizzled with the --tc-heuristic-recover switch to "
410
"commit or rollback pending transactions."),
411
recover_func.getMyXIDs(), opt_tc_log_file);
415
errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
419
int ha_start_consistent_snapshot(Session *session)
421
for_each(all_engines.begin(), all_engines.end(),
422
bind2nd(mem_fun(&StorageEngine::start_consistent_snapshot),session));
427
Ask handler if the table exists in engine.
429
HA_ERR_NO_SUCH_TABLE Table does not exist
431
HA_ERR_TABLE_EXIST Table exists
436
class TableExistsInStorageEngine: public unary_function<StorageEngine *,bool>
442
TableExistsInStorageEngine(Session *session_arg,
443
const char *db_arg, const char *name_arg)
444
:session(session_arg), db(db_arg), name(name_arg) {}
445
result_type operator() (argument_type engine)
447
int ret= engine->table_exists_in_engine(session, db, name);
448
return ret == HA_ERR_TABLE_EXIST;
453
Call this function in order to give the handler the possiblity
454
to ask engine if there are any new tables that should be written to disk
455
or any dropped tables that need to be removed from disk
457
int ha_table_exists_in_engine(Session* session,
458
const char* db, const char* name,
459
StorageEngine **engine_arg)
461
StorageEngine *engine= NULL;
464
drizzled::Registry<StorageEngine *>::iterator iter=
465
find_if(all_engines.begin(), all_engines.end(),
466
TableExistsInStorageEngine(session, db, name));
467
if (iter != all_engines.end())
474
/* Default way of knowing if a table exists. (checking .frm exists) */
476
char path[FN_REFLEN];
478
length= build_table_filename(path, sizeof(path),
481
if ((table_proto_exists(path) == EEXIST))
484
if (found && engine_arg)
486
drizzled::message::Table table;
487
strcpy(path + length, ".dfe");
488
if (drizzle_read_table_proto(path, &table) == 0)
490
LEX_STRING engine_name= { (char*)table.engine().name().c_str(),
491
strlen(table.engine().name().c_str()) };
492
engine= ha_resolve_by_name(session, &engine_name);
498
return HA_ERR_NO_SUCH_TABLE;
503
return HA_ERR_TABLE_EXIST;
506
int StorageEngine::renameTableImpl(Session *, const char *from, const char *to)
509
for (const char **ext= bas_ext(); *ext ; ext++)
511
if (rename_file_ext(from, to, *ext))
513
if ((error=my_errno) != ENOENT)
126
523
Delete all files with extension from bas_ext().
128
525
@param name Base name of table
131
We assume that the Cursor may return more extensions than
528
We assume that the handler may return more extensions than
132
529
was actually used for the file.
140
int StorageEngine::doDropTable(Session&, const TableIdentifier &identifier)
537
int StorageEngine::deleteTableImpl(Session *, const std::string table_path)
144
540
int enoent_or_zero= ENOENT; // Error if no file was deleted
145
541
char buff[FN_REFLEN];
147
for (const char **ext= bas_ext(); *ext ; ext++)
543
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);
151
if (internal::my_delete_with_symlink(buff, MYF(0)))
545
fn_format(buff, table_path.c_str(), "", *ext,
546
MY_UNPACK_FILENAME|MY_APPEND_EXT);
547
if (my_delete_with_symlink(buff, MYF(0)))
153
if ((error= errno) != ENOENT)
549
if ((error= my_errno) != ENOENT)
158
553
enoent_or_zero= 0; // No error for ENOENT
161
554
error= enoent_or_zero;
166
bool StorageEngine::addPlugin(StorageEngine *engine)
169
vector_of_engines.push_back(engine);
171
if (engine->getTableDefinitionFileExtension().length())
173
assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
174
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 *)
185
if (shutdown_has_begun == false)
187
vector_of_engines.clear();
188
vector_of_schema_engines.clear();
190
shutdown_has_begun= true;
194
class FindEngineByName
195
: public std::unary_function<StorageEngine *, bool>
197
const std::string &predicate;
200
explicit FindEngineByName(const std::string &target_arg) :
201
predicate(target_arg)
205
result_type operator() (argument_type engine)
207
return boost::iequals(engine->getName(), predicate);
211
StorageEngine *StorageEngine::findByName(const std::string &predicate)
213
EngineVector::iterator iter= std::find_if(vector_of_engines.begin(),
214
vector_of_engines.end(),
215
FindEngineByName(predicate));
216
if (iter != vector_of_engines.end())
218
StorageEngine *engine= *iter;
219
if (engine->is_user_selectable())
226
StorageEngine *StorageEngine::findByName(Session& session, const std::string &predicate)
228
if (boost::iequals(predicate, DEFAULT_STRING))
229
return session.getDefaultStorageEngine();
231
EngineVector::iterator iter= std::find_if(vector_of_engines.begin(),
232
vector_of_engines.end(),
233
FindEngineByName(predicate));
234
if (iter != vector_of_engines.end())
236
StorageEngine *engine= *iter;
237
if (engine->is_user_selectable())
244
class StorageEngineCloseConnection : public std::unary_function<StorageEngine *, void>
248
StorageEngineCloseConnection(Session *session_arg) : session(session_arg) {}
559
static const char *check_lowercase_names(handler *file, const char *path,
562
if ((file->ha_table_flags() & HA_FILE_BASED))
565
/* Ensure that table handler get path in lower case */
566
if (tmp_path != path)
567
strcpy(tmp_path, path);
250
there's no need to rollback here as all transactions must
251
be rolled back already
570
we only should turn into lowercase database/table part
571
so start the process after homedirectory
253
inline result_type operator() (argument_type engine)
255
if (*session->getEngineData(engine))
256
engine->close_connection(session);
262
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)
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())
281
if (engine->flush_logs())
287
class StorageEngineGetTableDefinition: public std::unary_function<StorageEngine *,bool>
290
const TableIdentifier &identifier;
291
message::Table &table_message;
295
StorageEngineGetTableDefinition(Session& session_arg,
296
const TableIdentifier &identifier_arg,
297
message::Table &table_message_arg,
299
session(session_arg),
300
identifier(identifier_arg),
301
table_message(table_message_arg),
304
result_type operator() (argument_type engine)
306
int ret= engine->doGetTableDefinition(session, identifier, table_message);
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";
365
Call this function in order to give the Cursor the possiblity
366
to ask engine if there are any new tables that should be written to disk
367
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)
376
if (include_temporary_tables)
378
Table *table= session.find_temporary_table(identifier);
381
table_message.reset(new message::Table(*table->getShare()->getTableProto()));
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);
573
my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
608
class DeleteTableStorageEngine
609
: public unary_function<StorageEngine *, void>
616
DeleteTableStorageEngine(Session *session_arg, const char *path_arg,
617
handler **file_arg, int *error_arg)
618
: session(session_arg), path(path_arg), file(file_arg), dt_error(error_arg) {}
620
result_type operator() (argument_type engine)
622
char tmp_path[FN_REFLEN];
625
if(*dt_error!=ENOENT) /* already deleted table */
631
if (!engine->is_enabled())
634
if ((tmp_file= engine->create(NULL, session->mem_root)))
639
path= check_lowercase_names(tmp_file, path, tmp_path);
640
const std::string table_path(path);
641
int tmp_error= engine->deleteTable(session, table_path);
643
if(tmp_error!=ENOENT)
645
*dt_error= tmp_error;
439
returns ENOENT if the file doesn't exists.
659
This should return ENOENT if the file doesn't exists.
660
The .frm file will be deleted only if we return 0 or ENOENT
441
int StorageEngine::dropTable(Session& session,
442
const TableIdentifier &identifier)
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);
480
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)))
662
int ha_delete_table(Session *session, const char *path,
663
const char *db, const char *alias, bool generate_warning)
665
TableShare dummy_share;
667
memset(&dummy_table, 0, sizeof(dummy_table));
668
memset(&dummy_share, 0, sizeof(dummy_share));
670
dummy_table.s= &dummy_share;
675
for_each(all_engines.begin(), all_engines.end(),
676
DeleteTableStorageEngine(session, path, &file, &error));
678
if (error && generate_warning)
681
Because file->print_error() use my_error() to generate the error message
682
we use an internal error handler to intercept it and store the text
683
in a temporary buffer. Later the message will be presented to user
686
Ha_delete_table_error_handler ha_delete_table_error_handler;
688
/* Fill up strucutures that print_error may need */
689
dummy_share.path.str= (char*) path;
690
dummy_share.path.length= strlen(path);
691
dummy_share.db.str= (char*) db;
692
dummy_share.db.length= strlen(db);
693
dummy_share.table_name.str= (char*) alias;
694
dummy_share.table_name.length= strlen(alias);
695
dummy_table.alias= alias;
503
error= ER_EVENT_OBSERVER_PLUGIN;
700
file->change_table_ptr(&dummy_table, &dummy_share);
702
session->push_internal_handler(&ha_delete_table_error_handler);
703
file->print_error(error, 0);
705
session->pop_internal_handler();
708
error= -1; /* General form of fail. maybe bad FRM */
711
XXX: should we convert *all* errors to warnings here?
712
What if the error is fatal?
714
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
715
ha_delete_table_error_handler.buff);
507
drizzled::message::Cache::singleton().erase(identifier);
514
725
Initiates table-file and calls appropriate database-creator.
521
int StorageEngine::createTable(Session &session,
522
const TableIdentifier &identifier,
523
message::Table& table_message)
732
int ha_create_table(Session *session, const char *path,
733
const char *db, const char *table_name,
734
HA_CREATE_INFO *create_info,
735
bool update_create_info)
526
TableShare share(identifier);
527
table::Shell table(share);
528
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.
739
char name_buff[FN_REFLEN];
741
TableShare share(db, 0, table_name, path);
743
if (open_table_def(session, &share) ||
744
open_table_from_share(session, &share, "", 0, (uint32_t) READ_ALL, 0, &table,
748
if (update_create_info)
749
table.updateCreateInfo(create_info);
751
name= check_lowercase_names(table.file, share.path.str, name_buff);
753
error= share.storage_engine->createTable(session, name, &table, create_info);
754
table.closefrm(false);
536
/* Check for legal operations against the Engine using the proto (if used) */
537
if (table_message.type() == message::Table::TEMPORARY &&
538
share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
540
error= HA_ERR_UNSUPPORTED;
542
else if (table_message.type() != message::Table::TEMPORARY &&
543
share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
545
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();
757
sprintf(name_buff,"%s.%s",db,table_name);
758
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
761
share.free_table_share();
567
762
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;
584
AddTableIdentifier(CachedDirectory &directory_arg, const SchemaIdentifier &identifier_arg, TableIdentifier::vector &of_names) :
585
directory(directory_arg),
586
identifier(identifier_arg),
587
set_of_identifiers(of_names)
591
result_type operator() (argument_type engine)
593
engine->doGetTableIdentifiers(directory, identifier, set_of_identifiers);
598
void StorageEngine::getIdentifiers(Session &session, const SchemaIdentifier &schema_identifier, TableIdentifier::vector &set_of_identifiers)
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)
611
if (directory.fail())
613
errno= directory.getError();
617
schema_identifier.getSQLPath(path);
618
my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), path.c_str());
622
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);
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
/* This will later be converted to TableIdentifiers */
654
class DropTables: public std::unary_function<StorageEngine *, void>
657
TableIdentifier::vector &table_identifiers;
661
DropTables(Session &session_arg, TableIdentifier::vector &table_identifiers_arg) :
662
session(session_arg),
663
table_identifiers(table_identifiers_arg)
666
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());
678
This only works for engines which use file based DFE.
680
Note-> Unlike MySQL, we do not, on purpose, delete files that do not match any engines.
682
void StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
684
CachedDirectory dir(directory, set_of_table_definition_ext);
685
TableIdentifier::vector table_identifiers;
689
errno= dir.getError();
690
my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
695
CachedDirectory::Entries files= dir.getEntries();
697
for (CachedDirectory::Entries::iterator fileIter= files.begin();
698
fileIter != files.end(); fileIter++)
702
CachedDirectory::Entry *entry= *fileIter;
704
/* We remove the file extension. */
705
length= entry->filename.length();
706
entry->filename.resize(length - DEFAULT_DEFINITION_FILE_EXT.length());
710
path+= entry->filename;
711
message::Table definition;
712
if (StorageEngine::readTableFile(path, definition))
714
TableIdentifier identifier(definition.schema(), definition.name(), path);
715
table_identifiers.push_back(identifier);
719
std::for_each(vector_of_engines.begin(), vector_of_engines.end(),
720
DropTables(session, table_identifiers));
723
Now we just clean up anything that might left over.
725
We rescan because some of what might have been there should
726
now be all nice and cleaned up.
728
std::set<std::string> all_exts= set_of_table_definition_ext;
730
for (EngineVector::iterator iter= vector_of_engines.begin();
731
iter != vector_of_engines.end() ; iter++)
733
for (const char **ext= (*iter)->bas_ext(); *ext ; ext++)
734
all_exts.insert(*ext);
737
CachedDirectory rescan(directory, all_exts);
739
files= rescan.getEntries();
740
for (CachedDirectory::Entries::iterator fileIter= files.begin();
741
fileIter != files.end(); fileIter++)
744
CachedDirectory::Entry *entry= *fileIter;
748
path+= entry->filename;
750
unlink(path.c_str());
756
Print error that we got from Cursor function.
759
In case of delete table it's only safe to use the following parts of
760
the 'table' structure:
761
- table->getShare()->path
764
void StorageEngine::print_error(int error, myf errflag, Table &table)
766
print_error(error, errflag, &table);
769
void StorageEngine::print_error(int error, myf errflag, Table *table)
771
int textno= ER_GET_ERRNO;
774
textno=ER_OPEN_AS_READONLY;
780
textno=ER_FILE_NOT_FOUND;
782
case HA_ERR_KEY_NOT_FOUND:
783
case HA_ERR_NO_ACTIVE_RECORD:
784
case HA_ERR_END_OF_FILE:
785
textno=ER_KEY_NOT_FOUND;
787
case HA_ERR_WRONG_MRG_TABLE_DEF:
788
textno=ER_WRONG_MRG_TABLE;
790
case HA_ERR_FOUND_DUPP_KEY:
793
uint32_t key_nr= table->get_dup_key(error);
794
if ((int) key_nr >= 0)
796
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
798
print_keydup_error(key_nr, err_msg, *table);
805
case HA_ERR_FOREIGN_DUPLICATE_KEY:
808
uint32_t key_nr= table->get_dup_key(error);
809
if ((int) key_nr >= 0)
813
/* Write the key in the error message */
814
char key[MAX_KEY_LENGTH];
815
String str(key,sizeof(key),system_charset_info);
817
/* Table is opened and defined at this point */
818
key_unpack(&str,table,(uint32_t) key_nr);
819
max_length= (DRIZZLE_ERRMSG_SIZE-
820
(uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
821
if (str.length() >= max_length)
823
str.length(max_length-4);
824
str.append(STRING_WITH_LEN("..."));
826
my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table->getShare()->getTableName(),
827
str.c_ptr(), key_nr+1);
833
case HA_ERR_FOUND_DUPP_UNIQUE:
834
textno=ER_DUP_UNIQUE;
836
case HA_ERR_RECORD_CHANGED:
840
textno=ER_NOT_KEYFILE;
842
case HA_ERR_WRONG_IN_RECORD:
843
textno= ER_CRASHED_ON_USAGE;
845
case HA_ERR_CRASHED_ON_USAGE:
846
textno=ER_CRASHED_ON_USAGE;
848
case HA_ERR_NOT_A_TABLE:
851
case HA_ERR_CRASHED_ON_REPAIR:
852
textno=ER_CRASHED_ON_REPAIR;
854
case HA_ERR_OUT_OF_MEM:
855
textno=ER_OUT_OF_RESOURCES;
857
case HA_ERR_WRONG_COMMAND:
858
textno=ER_ILLEGAL_HA;
860
case HA_ERR_OLD_FILE:
861
textno=ER_OLD_KEYFILE;
863
case HA_ERR_UNSUPPORTED:
864
textno=ER_UNSUPPORTED_EXTENSION;
866
case HA_ERR_RECORD_FILE_FULL:
867
case HA_ERR_INDEX_FILE_FULL:
868
textno=ER_RECORD_FILE_FULL;
870
case HA_ERR_LOCK_WAIT_TIMEOUT:
871
textno=ER_LOCK_WAIT_TIMEOUT;
873
case HA_ERR_LOCK_TABLE_FULL:
874
textno=ER_LOCK_TABLE_FULL;
876
case HA_ERR_LOCK_DEADLOCK:
877
textno=ER_LOCK_DEADLOCK;
879
case HA_ERR_READ_ONLY_TRANSACTION:
880
textno=ER_READ_ONLY_TRANSACTION;
882
case HA_ERR_CANNOT_ADD_FOREIGN:
883
textno=ER_CANNOT_ADD_FOREIGN;
885
case HA_ERR_ROW_IS_REFERENCED:
888
get_error_message(error, &str);
889
my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
892
case HA_ERR_NO_REFERENCED_ROW:
895
get_error_message(error, &str);
896
my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
899
case HA_ERR_TABLE_DEF_CHANGED:
900
textno=ER_TABLE_DEF_CHANGED;
902
case HA_ERR_NO_SUCH_TABLE:
904
my_error(ER_NO_SUCH_TABLE, MYF(0), table->getShare()->getSchemaName(),
905
table->getShare()->getTableName());
907
case HA_ERR_RBR_LOGGING_FAILED:
908
textno= ER_BINLOG_ROW_LOGGING_FAILED;
910
case HA_ERR_DROP_INDEX_FK:
913
const char *ptr= "???";
914
uint32_t key_nr= table->get_dup_key(error);
915
if ((int) key_nr >= 0)
916
ptr= table->key_info[key_nr].name;
917
my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
920
case HA_ERR_TABLE_NEEDS_UPGRADE:
921
textno=ER_TABLE_NEEDS_UPGRADE;
923
case HA_ERR_TABLE_READONLY:
924
textno= ER_OPEN_AS_READONLY;
926
case HA_ERR_AUTOINC_READ_FAILED:
927
textno= ER_AUTOINC_READ_FAILED;
929
case HA_ERR_AUTOINC_ERANGE:
930
textno= ER_WARN_DATA_OUT_OF_RANGE;
932
case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
933
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
934
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
939
The error was "unknown" to this function.
940
Ask Cursor if it has got a message for this error
942
bool temporary= false;
944
temporary= get_error_message(error, &str);
947
const char* engine_name= getName().c_str();
949
my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(),
952
my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
956
my_error(ER_GET_ERRNO,errflag,error);
961
my_error(textno, errflag, table->getShare()->getTableName(), error);
966
Return an error message specific to this Cursor.
968
@param error error code previously returned by Cursor
969
@param buf pointer to String where to add error message
972
Returns true if this is a temporary error
974
bool StorageEngine::get_error_message(int , String* )
980
void StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, Table &table)
982
/* Write the duplicated key in the error message */
983
char key[MAX_KEY_LENGTH];
984
String str(key,sizeof(key),system_charset_info);
986
if (key_nr == MAX_KEY)
989
str.copy("", 0, system_charset_info);
990
my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
994
/* Table is opened and defined at this point */
995
key_unpack(&str, &table, (uint32_t) key_nr);
996
uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
997
if (str.length() >= max_length)
999
str.length(max_length-4);
1000
str.append(STRING_WITH_LEN("..."));
1002
my_printf_error(ER_DUP_ENTRY, msg,
1003
MYF(0), str.c_ptr(), table.key_info[key_nr].name);
1008
int StorageEngine::deleteDefinitionFromPath(const TableIdentifier &identifier)
1010
std::string path(identifier.getPath());
1012
path.append(DEFAULT_DEFINITION_FILE_EXT);
1014
return internal::my_delete(path.c_str(), MYF(0));
1017
int StorageEngine::renameDefinitionFromPath(const TableIdentifier &dest, const TableIdentifier &src)
1019
message::Table table_message;
1020
std::string src_path(src.getPath());
1021
std::string dest_path(dest.getPath());
1023
src_path.append(DEFAULT_DEFINITION_FILE_EXT);
1024
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());
1046
int StorageEngine::writeDefinitionFromPath(const TableIdentifier &identifier, message::Table &table_message)
1048
char definition_file_tmp[FN_REFLEN];
1049
std::string file_name(identifier.getPath());
1051
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);
1059
perror(definition_file_tmp);
1063
google::protobuf::io::ZeroCopyOutputStream* output=
1064
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());
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
} /* namespace drizzled */
766
const string ha_resolve_storage_engine_name(const StorageEngine *engine)
768
return engine == NULL ? string("UNKNOWN") : engine->getName();