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;
126
Delete all files with extension from bas_ext().
128
@param name Base name of table
131
We assume that the Cursor may return more extensions than
132
was actually used for the file.
135
0 If we successfully deleted at least one file from base_ext and
136
didn't get any other errors than ENOENT
140
int StorageEngine::doDropTable(Session&, const TableIdentifier &identifier)
144
int enoent_or_zero= ENOENT; // Error if no file was deleted
145
char buff[FN_REFLEN];
147
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)))
153
if ((error= errno) != ENOENT)
158
enoent_or_zero= 0; // No error for ENOENT
161
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>
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;
84
Return the default storage engine StorageEngine for thread
86
@param ha_default_storage_engine(session)
87
@param session current thread
90
pointer to StorageEngine
92
StorageEngine *ha_default_storage_engine(Session *session)
94
if (session->variables.storage_engine)
95
return session->variables.storage_engine;
96
return global_system_variables.storage_engine;
101
Return the storage engine StorageEngine for the supplied name
103
@param session current thread
104
@param name name of storage engine
107
pointer to storage engine plugin handle
109
StorageEngine *ha_resolve_by_name(Session *session, const LEX_STRING *name)
112
string find_str(name->str, name->length);
113
transform(find_str.begin(), find_str.end(),
114
find_str.begin(), ::tolower);
115
string default_str("default");
116
if (find_str == default_str)
117
return ha_default_storage_engine(session);
120
StorageEngine *engine= all_engines.find(find_str);
122
if (engine && engine->is_user_selectable())
129
handler *get_new_handler(TABLE_SHARE *share, MEM_ROOT *alloc,
130
StorageEngine *engine)
134
if (engine && engine->is_enabled())
136
if ((file= engine->create(share, alloc)))
141
Try the default table type
142
Here the call to current_session() is ok as we call this function a lot of
143
times but we enter this branch very seldom.
145
return(get_new_handler(share, alloc, ha_default_storage_engine(current_session)));
148
class StorageEngineCloseConnection
149
: public unary_function<StorageEngine *, void>
246
151
Session *session;
262
168
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)
170
void ha_close_connection(Session* session)
172
for_each(all_engines.begin(), all_engines.end(),
173
StorageEngineCloseConnection(session));
176
void ha_drop_database(char* path)
178
for_each(all_engines.begin(), all_engines.end(),
179
bind2nd(mem_fun(&StorageEngine::drop_database),path));
182
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
187
transform(all_engines.begin(), all_engines.end(), results.begin(),
188
bind2nd(mem_fun(&StorageEngine::commit_by_xid),xid));
190
transform(all_engines.begin(), all_engines.end(), results.begin(),
191
bind2nd(mem_fun(&StorageEngine::rollback_by_xid),xid));
193
if (find_if(results.begin(), results.end(), bind2nd(equal_to<int>(),0))
202
This function should be called when MySQL sends rows of a SELECT result set
203
or the EOF mark to the client. It releases a possible adaptive hash index
204
S-latch held by session in InnoDB and also releases a possible InnoDB query
205
FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
206
keep them over several calls of the InnoDB handler interface when a join
207
is executed. But when we let the control to pass to the client they have
208
to be released because if the application program uses mysql_use_result(),
209
it may deadlock on the S-latch if the application on another connection
210
performs another SQL query. In MySQL-4.1 this is even more important because
211
there a connection can have several SELECT queries open at the same time.
213
@param session the thread handle of the current connection
218
int ha_release_temporary_latches(Session *session)
220
for_each(all_engines.begin(), all_engines.end(),
221
bind2nd(mem_fun(&StorageEngine::release_temporary_latches),session));
226
bool ha_flush_logs(StorageEngine *engine)
272
228
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())
230
if (find_if(all_engines.begin(), all_engines.end(),
231
mem_fun(&StorageEngine::flush_logs))
232
!= all_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
237
if ((!engine->is_enabled()) ||
238
(engine->flush_logs()))
245
recover() step of xa.
248
there are three modes of operation:
249
- automatic recover after a crash
250
in this case commit_list != 0, tc_heuristic_recover==0
251
all xids from commit_list are committed, others are rolled back
252
- manual (heuristic) recover
253
in this case commit_list==0, tc_heuristic_recover != 0
254
DBA has explicitly specified that all prepared transactions should
255
be committed (or rolled back).
256
- no recovery (MySQL did not detect a crash)
257
in this case commit_list==0, tc_heuristic_recover == 0
258
there should be no prepared transactions in this case.
260
class XARecover : unary_function<StorageEngine *, void>
262
int trans_len, found_foreign_xids, found_my_xids;
268
XARecover(XID *trans_list_arg, int trans_len_arg,
269
HASH *commit_list_arg, bool dry_run_arg)
270
: trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
271
trans_list(trans_list_arg), commit_list(commit_list_arg),
277
return found_foreign_xids;
282
return found_my_xids;
285
result_type operator() (argument_type engine)
290
if (engine->is_enabled())
292
while ((got= engine->recover(trans_list, trans_len)) > 0 )
294
errmsg_printf(ERRMSG_LVL_INFO,
295
_("Found %d prepared transaction(s) in %s"),
296
got, engine->getName().c_str());
297
for (int i=0; i < got; i ++)
299
my_xid x=trans_list[i].get_my_xid();
300
if (!x) // not "mine" - that is generated by external TM
302
xid_cache_insert(trans_list+i, XA_PREPARED);
303
found_foreign_xids++;
313
hash_search(commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
314
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
316
engine->commit_by_xid(trans_list+i);
320
engine->rollback_by_xid(trans_list+i);
331
int ha_recover(HASH *commit_list)
333
XID *trans_list= NULL;
336
bool dry_run= (commit_list==0 && tc_heuristic_recover==0);
338
/* commit_list and tc_heuristic_recover cannot be set both */
339
assert(commit_list==0 || tc_heuristic_recover==0);
341
/* if either is set, total_ha_2pc must be set too */
342
if (total_ha_2pc <= 1)
346
#ifndef WILL_BE_DELETED_LATER
349
for now, only InnoDB supports 2pc. It means we can always safely
350
rollback all pending transactions, without risking inconsistent data
353
assert(total_ha_2pc == 2); // only InnoDB and binlog
354
tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
357
for (trans_len= MAX_XID_LIST_SIZE ;
358
trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
360
trans_list=(XID *)malloc(trans_len*sizeof(XID));
364
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
369
errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
372
XARecover recover_func(trans_list, trans_len, commit_list, dry_run);
373
for_each(all_engines.begin(), all_engines.end(), recover_func);
376
if (recover_func.getForeignXIDs())
377
errmsg_printf(ERRMSG_LVL_WARN,
378
_("Found %d prepared XA transactions"),
379
recover_func.getForeignXIDs());
380
if (dry_run && recover_func.getMyXIDs())
382
errmsg_printf(ERRMSG_LVL_ERROR,
383
_("Found %d prepared transactions! It means that drizzled "
384
"was not shut down properly last time and critical "
385
"recovery information (last binlog or %s file) was "
386
"manually deleted after a crash. You have to start "
387
"drizzled with the --tc-heuristic-recover switch to "
388
"commit or rollback pending transactions."),
389
recover_func.getMyXIDs(), opt_tc_log_file);
393
errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
397
int ha_start_consistent_snapshot(Session *session)
399
for_each(all_engines.begin(), all_engines.end(),
400
bind2nd(mem_fun(&StorageEngine::start_consistent_snapshot),session));
405
Ask handler if the table exists in engine.
407
HA_ERR_NO_SUCH_TABLE Table does not exist
409
HA_ERR_TABLE_EXIST Table exists
414
class TableExistsInStorageEngine: public unary_function<StorageEngine *,bool>
420
TableExistsInStorageEngine(Session *session_arg,
421
const char *db_arg, const char *name_arg)
422
:session(session_arg), db(db_arg), name(name_arg) {}
423
result_type operator() (argument_type engine)
425
int ret= engine->table_exists_in_engine(session, db, name);
426
return ret == HA_ERR_TABLE_EXIST;
431
Call this function in order to give the handler the possiblity
366
432
to ask engine if there are any new tables that should be written to disk
367
433
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)
435
int ha_table_exists_in_engine(Session* session,
436
const char* db, const char* name,
437
StorageEngine **engine_arg)
376
if (include_temporary_tables)
378
Table *table= session.find_temporary_table(identifier);
439
StorageEngine *engine= NULL;
441
drizzled::Registry<StorageEngine *>::iterator iter=
442
find_if(all_engines.begin(), all_engines.end(),
443
TableExistsInStorageEngine(session, db, name));
444
if (iter != all_engines.end())
450
/* Default way of knowing if a table exists. (checking .frm exists) */
452
char path[FN_REFLEN];
453
build_table_filename(path, sizeof(path),
455
if (table_proto_exists(path)==EEXIST)
381
table_message.reset(new message::Table(*table->getShare()->getTableProto()));
457
drizzled::message::Table table;
458
build_table_filename(path, sizeof(path),
459
db, name, ".dfe", 0);
460
if(drizzle_read_table_proto(path, &table)==0)
462
LEX_STRING engine_name= { (char*)table.engine().name().c_str(),
463
strlen(table.engine().name().c_str()) };
464
engine= ha_resolve_by_name(session, &engine_name);
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);
473
return HA_ERR_NO_SUCH_TABLE;
474
return HA_ERR_TABLE_EXIST;
478
static const char *check_lowercase_names(handler *file, const char *path,
481
if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED))
484
/* Ensure that table handler get path in lower case */
485
if (tmp_path != path)
486
strcpy(tmp_path, path);
489
we only should turn into lowercase database/table part
490
so start the process after homedirectory
492
my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
527
class DeleteTableStorageEngine
528
: public unary_function<StorageEngine *, void>
535
DeleteTableStorageEngine(Session *session_arg, const char *path_arg,
536
handler **file_arg, int *error_arg)
537
: session(session_arg), path(path_arg), file(file_arg), dt_error(error_arg) {}
539
result_type operator() (argument_type engine)
543
char tmp_path[FN_REFLEN];
545
if(*dt_error!=ENOENT) /* already deleted table */
551
if (!engine->is_enabled())
554
if ((tmp_file= engine->create(NULL, session->mem_root)))
559
path= check_lowercase_names(tmp_file, path, tmp_path);
560
int tmp_error= tmp_file->ha_delete_table(path);
562
if(tmp_error!=ENOENT)
564
*dt_error= tmp_error;
439
returns ENOENT if the file doesn't exists.
578
This should return ENOENT if the file doesn't exists.
579
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)))
581
int ha_delete_table(Session *session, const char *path,
582
const char *db, const char *alias, bool generate_warning)
584
TABLE_SHARE dummy_share;
586
memset(&dummy_table, 0, sizeof(dummy_table));
587
memset(&dummy_share, 0, sizeof(dummy_share));
589
dummy_table.s= &dummy_share;
594
for_each(all_engines.begin(), all_engines.end(),
595
DeleteTableStorageEngine(session, path, &file, &error));
597
if (error && generate_warning)
600
Because file->print_error() use my_error() to generate the error message
601
we use an internal error handler to intercept it and store the text
602
in a temporary buffer. Later the message will be presented to user
605
Ha_delete_table_error_handler ha_delete_table_error_handler;
607
/* Fill up strucutures that print_error may need */
608
dummy_share.path.str= (char*) path;
609
dummy_share.path.length= strlen(path);
610
dummy_share.db.str= (char*) db;
611
dummy_share.db.length= strlen(db);
612
dummy_share.table_name.str= (char*) alias;
613
dummy_share.table_name.length= strlen(alias);
614
dummy_table.alias= alias;
503
error= ER_EVENT_OBSERVER_PLUGIN;
619
file->change_table_ptr(&dummy_table, &dummy_share);
621
session->push_internal_handler(&ha_delete_table_error_handler);
622
file->print_error(error, 0);
624
session->pop_internal_handler();
627
error= -1; /* General form of fail. maybe bad FRM */
630
XXX: should we convert *all* errors to warnings here?
631
What if the error is fatal?
633
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
634
ha_delete_table_error_handler.buff);
507
drizzled::message::Cache::singleton().erase(identifier);
514
644
Initiates table-file and calls appropriate database-creator.
521
int StorageEngine::createTable(Session &session,
522
const TableIdentifier &identifier,
523
message::Table& table_message)
651
int ha_create_table(Session *session, const char *path,
652
const char *db, const char *table_name,
653
HA_CREATE_INFO *create_info,
654
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.
658
char name_buff[FN_REFLEN];
662
init_tmp_table_share(session, &share, db, 0, table_name, path);
663
if (open_table_def(session, &share, 0) ||
664
open_table_from_share(session, &share, "", 0, (uint32_t) READ_ALL, 0, &table,
668
if (update_create_info)
669
table.updateCreateInfo(create_info);
671
name= check_lowercase_names(table.file, share.path.str, name_buff);
673
error= table.file->ha_create(name, &table, create_info);
674
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();
677
sprintf(name_buff,"%s.%s",db,table_name);
678
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
681
free_table_share(&share);
567
682
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 */
686
const string ha_resolve_storage_engine_name(const StorageEngine *engine)
688
return engine == NULL ? string("UNKNOWN") : engine->getName();