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/my_hash.h"
36
#include "drizzled/cached_directory.h"
20
#include <drizzled/server_includes.h>
38
21
#include <drizzled/definitions.h>
39
22
#include <drizzled/base.h>
40
#include <drizzled/cursor.h>
23
#include <drizzled/handler.h>
41
24
#include <drizzled/plugin/storage_engine.h>
42
25
#include <drizzled/session.h>
43
26
#include <drizzled/error.h>
44
27
#include <drizzled/gettext.h>
28
#include <drizzled/registry.h>
45
29
#include <drizzled/unireg.h>
46
30
#include <drizzled/data_home.h>
47
#include "drizzled/errmsg_print.h"
48
#include "drizzled/xid.h"
49
#include "drizzled/sql_table.h"
50
#include "drizzled/global_charset_info.h"
51
#include "drizzled/charset.h"
52
#include "drizzled/internal/my_sys.h"
53
#include "drizzled/db.h"
31
#include <drizzled/plugin_registry.h>
55
34
#include <drizzled/table_proto.h>
57
static bool shutdown_has_begun= false; // Once we put in the container for the vector/etc for engines this will go away.
36
#include <google/protobuf/io/zero_copy_stream.h>
37
#include <google/protobuf/io/zero_copy_stream_impl.h>
39
#include <mysys/my_dir.h>
59
43
using namespace std;
67
static EngineVector vector_of_engines;
68
static EngineVector vector_of_schema_engines;
70
const std::string UNKNOWN_STRING("UNKNOWN");
71
const std::string DEFAULT_DEFINITION_FILE_EXT(".dfe");
73
static std::set<std::string> set_of_table_definition_ext;
75
EngineVector &StorageEngine::getSchemaEngines()
77
return vector_of_schema_engines;
80
StorageEngine::StorageEngine(const string name_arg,
81
const bitset<HTON_BIT_SIZE> &flags_arg) :
82
Plugin(name_arg, "StorageEngine"),
83
MonitoredInTransaction(), /* This gives the storage engine a "slot" or ID */
45
drizzled::Registry<StorageEngine *> all_engines;
47
void add_storage_engine(StorageEngine *engine)
49
all_engines.add(engine);
52
void remove_storage_engine(StorageEngine *engine)
54
all_engines.remove(engine);
57
StorageEngine::StorageEngine(const std::string name_arg,
58
const std::bitset<HTON_BIT_SIZE> &flags_arg,
59
size_t savepoint_offset_arg,
61
: name(name_arg), two_phase_commit(support_2pc), enabled(true),
63
savepoint_offset(savepoint_alloc_size),
64
orig_savepoint_offset(savepoint_offset_arg),
69
savepoint_alloc_size+= orig_savepoint_offset;
88
77
StorageEngine::~StorageEngine()
92
void StorageEngine::setTransactionReadWrite(Session& session)
94
TransactionContext &statement_ctx= session.transaction.stmt;
95
statement_ctx.markModifiedNonTransData();
99
int StorageEngine::renameTable(Session &session, TableIdentifier &from, TableIdentifier &to)
101
setTransactionReadWrite(session);
103
return doRenameTable(session, from, to);
107
Delete all files with extension from bas_ext().
109
@param name Base name of table
112
We assume that the Cursor may return more extensions than
113
was actually used for the file.
116
0 If we successfully deleted at least one file from base_ext and
117
didn't get any other errors than ENOENT
121
int StorageEngine::doDropTable(Session&, TableIdentifier &identifier)
125
int enoent_or_zero= ENOENT; // Error if no file was deleted
126
char buff[FN_REFLEN];
128
for (const char **ext= bas_ext(); *ext ; ext++)
130
internal::fn_format(buff, identifier.getPath().c_str(), "", *ext,
131
MY_UNPACK_FILENAME|MY_APPEND_EXT);
132
if (internal::my_delete_with_symlink(buff, MYF(0)))
134
if ((error= errno) != ENOENT)
139
enoent_or_zero= 0; // No error for ENOENT
142
error= enoent_or_zero;
147
bool StorageEngine::addPlugin(StorageEngine *engine)
150
vector_of_engines.push_back(engine);
152
if (engine->getTableDefinitionFileExtension().length())
154
assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
155
set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
158
if (engine->check_flag(HTON_BIT_SCHEMA_DICTIONARY))
159
vector_of_schema_engines.push_back(engine);
164
void StorageEngine::removePlugin(StorageEngine *)
166
if (shutdown_has_begun == false)
168
vector_of_engines.clear();
169
vector_of_schema_engines.clear();
171
shutdown_has_begun= true;
175
class FindEngineByName
176
: public unary_function<StorageEngine *, bool>
178
const string ⌖
181
explicit FindEngineByName(const string &target_arg) :
185
result_type operator() (argument_type engine)
187
string engine_name(engine->getName());
189
transform(engine_name.begin(), engine_name.end(),
190
engine_name.begin(), ::tolower);
191
return engine_name == target;
195
StorageEngine *StorageEngine::findByName(const string &find_str)
197
string search_string(find_str);
198
transform(search_string.begin(), search_string.end(),
199
search_string.begin(), ::tolower);
202
EngineVector::iterator iter= find_if(vector_of_engines.begin(),
203
vector_of_engines.end(),
204
FindEngineByName(search_string));
205
if (iter != vector_of_engines.end())
207
StorageEngine *engine= *iter;
208
if (engine->is_user_selectable())
215
StorageEngine *StorageEngine::findByName(Session& session, const string &find_str)
217
string search_string(find_str);
218
transform(search_string.begin(), search_string.end(),
219
search_string.begin(), ::tolower);
221
if (search_string.compare("default") == 0)
222
return session.getDefaultStorageEngine();
224
EngineVector::iterator iter= find_if(vector_of_engines.begin(),
225
vector_of_engines.end(),
226
FindEngineByName(search_string));
227
if (iter != vector_of_engines.end())
229
StorageEngine *engine= *iter;
230
if (engine->is_user_selectable())
237
class StorageEngineCloseConnection : public unary_function<StorageEngine *, void>
79
savepoint_alloc_size-= orig_savepoint_offset;
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
ha_info->set_trx_read_write();
105
Return the default storage engine StorageEngine for thread
107
@param ha_default_storage_engine(session)
108
@param session current thread
111
pointer to StorageEngine
113
StorageEngine *ha_default_storage_engine(Session *session)
115
if (session->variables.storage_engine)
116
return session->variables.storage_engine;
117
return global_system_variables.storage_engine;
122
Return the storage engine StorageEngine for the supplied name
124
@param session current thread
125
@param name name of storage engine
128
pointer to storage engine plugin handle
130
StorageEngine *ha_resolve_by_name(Session *session, std::string find_str)
132
transform(find_str.begin(), find_str.end(),
133
find_str.begin(), ::tolower);
134
string default_str("default");
135
if (find_str == default_str)
136
return ha_default_storage_engine(session);
138
StorageEngine *engine= all_engines.find(find_str);
140
if (engine && engine->is_user_selectable())
147
handler *get_new_handler(TableShare *share, MEM_ROOT *alloc,
148
StorageEngine *engine)
152
if (engine && engine->is_enabled())
154
if ((file= engine->create(share, alloc)))
159
Try the default table type
160
Here the call to current_session() is ok as we call this function a lot of
161
times but we enter this branch very seldom.
163
return(get_new_handler(share, alloc, ha_default_storage_engine(current_session)));
166
class StorageEngineCloseConnection
167
: public unary_function<StorageEngine *, void>
239
169
Session *session;
255
186
don't bother to rollback here, it's done already
257
void StorageEngine::closeConnection(Session* session)
188
void ha_close_connection(Session* session)
259
for_each(vector_of_engines.begin(), vector_of_engines.end(),
190
for_each(all_engines.begin(), all_engines.end(),
260
191
StorageEngineCloseConnection(session));
263
bool StorageEngine::flushLogs(StorageEngine *engine)
194
void ha_drop_database(char* path)
196
for_each(all_engines.begin(), all_engines.end(),
197
bind2nd(mem_fun(&StorageEngine::drop_database),path));
200
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
205
transform(all_engines.begin(), all_engines.end(), results.begin(),
206
bind2nd(mem_fun(&StorageEngine::commit_by_xid),xid));
208
transform(all_engines.begin(), all_engines.end(), results.begin(),
209
bind2nd(mem_fun(&StorageEngine::rollback_by_xid),xid));
211
if (find_if(results.begin(), results.end(), bind2nd(equal_to<int>(),0))
220
This function should be called when MySQL sends rows of a SELECT result set
221
or the EOF mark to the client. It releases a possible adaptive hash index
222
S-latch held by session in InnoDB and also releases a possible InnoDB query
223
FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
224
keep them over several calls of the InnoDB handler interface when a join
225
is executed. But when we let the control to pass to the client they have
226
to be released because if the application program uses mysql_use_result(),
227
it may deadlock on the S-latch if the application on another connection
228
performs another SQL query. In MySQL-4.1 this is even more important because
229
there a connection can have several SELECT queries open at the same time.
231
@param session the thread handle of the current connection
236
int ha_release_temporary_latches(Session *session)
238
for_each(all_engines.begin(), all_engines.end(),
239
bind2nd(mem_fun(&StorageEngine::release_temporary_latches),session));
244
bool ha_flush_logs(StorageEngine *engine)
265
246
if (engine == NULL)
267
if (find_if(vector_of_engines.begin(), vector_of_engines.end(),
268
mem_fun(&StorageEngine::flush_logs))
269
!= vector_of_engines.begin())
248
if (find_if(all_engines.begin(), all_engines.end(),
249
mem_fun(&StorageEngine::flush_logs))
250
!= all_engines.begin())
274
if (engine->flush_logs())
255
if ((!engine->is_enabled()) ||
256
(engine->flush_logs()))
280
class StorageEngineGetTableDefinition: public unary_function<StorageEngine *,bool>
283
TableIdentifier &identifier;
284
message::Table &table_message;
288
StorageEngineGetTableDefinition(Session& session_arg,
289
TableIdentifier &identifier_arg,
290
message::Table &table_message_arg,
292
session(session_arg),
293
identifier(identifier_arg),
294
table_message(table_message_arg),
297
result_type operator() (argument_type engine)
299
int ret= engine->doGetTableDefinition(session, identifier, table_message);
263
recover() step of xa.
266
there are three modes of operation:
267
- automatic recover after a crash
268
in this case commit_list != 0, tc_heuristic_recover==0
269
all xids from commit_list are committed, others are rolled back
270
- manual (heuristic) recover
271
in this case commit_list==0, tc_heuristic_recover != 0
272
DBA has explicitly specified that all prepared transactions should
273
be committed (or rolled back).
274
- no recovery (MySQL did not detect a crash)
275
in this case commit_list==0, tc_heuristic_recover == 0
276
there should be no prepared transactions in this case.
278
class XARecover : unary_function<StorageEngine *, void>
280
int trans_len, found_foreign_xids, found_my_xids;
286
XARecover(XID *trans_list_arg, int trans_len_arg,
287
HASH *commit_list_arg, bool dry_run_arg)
288
: trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
290
trans_list(trans_list_arg), commit_list(commit_list_arg),
296
return found_foreign_xids;
301
return found_my_xids;
304
result_type operator() (argument_type engine)
309
if (engine->is_enabled())
311
while ((got= engine->recover(trans_list, trans_len)) > 0 )
313
errmsg_printf(ERRMSG_LVL_INFO,
314
_("Found %d prepared transaction(s) in %s"),
315
got, engine->getName().c_str());
316
for (int i=0; i < got; i ++)
318
my_xid x=trans_list[i].get_my_xid();
319
if (!x) // not "mine" - that is generated by external TM
321
xid_cache_insert(trans_list+i, XA_PREPARED);
322
found_foreign_xids++;
332
hash_search(commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
333
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
335
engine->commit_by_xid(trans_list+i);
339
engine->rollback_by_xid(trans_list+i);
350
int ha_recover(HASH *commit_list)
352
XID *trans_list= NULL;
355
bool dry_run= (commit_list==0 && tc_heuristic_recover==0);
357
/* commit_list and tc_heuristic_recover cannot be set both */
358
assert(commit_list==0 || tc_heuristic_recover==0);
360
/* if either is set, total_ha_2pc must be set too */
361
if (total_ha_2pc <= 1)
365
#ifndef WILL_BE_DELETED_LATER
368
for now, only InnoDB supports 2pc. It means we can always safely
369
rollback all pending transactions, without risking inconsistent data
372
assert(total_ha_2pc == 2); // only InnoDB and binlog
373
tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
376
for (trans_len= MAX_XID_LIST_SIZE ;
377
trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
379
trans_list=(XID *)malloc(trans_len*sizeof(XID));
383
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
388
errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
391
XARecover recover_func(trans_list, trans_len, commit_list, dry_run);
392
for_each(all_engines.begin(), all_engines.end(), recover_func);
395
if (recover_func.getForeignXIDs())
396
errmsg_printf(ERRMSG_LVL_WARN,
397
_("Found %d prepared XA transactions"),
398
recover_func.getForeignXIDs());
399
if (dry_run && recover_func.getMyXIDs())
401
errmsg_printf(ERRMSG_LVL_ERROR,
402
_("Found %d prepared transactions! It means that drizzled "
403
"was not shut down properly last time and critical "
404
"recovery information (last binlog or %s file) was "
405
"manually deleted after a crash. You have to start "
406
"drizzled with the --tc-heuristic-recover switch to "
407
"commit or rollback pending transactions."),
408
recover_func.getMyXIDs(), opt_tc_log_file);
412
errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
416
int ha_start_consistent_snapshot(Session *session)
418
for_each(all_engines.begin(), all_engines.end(),
419
bind2nd(mem_fun(&StorageEngine::start_consistent_snapshot),session));
423
static int drizzle_read_table_proto(const char* path, drizzled::message::Table* table)
425
int fd= open(path, O_RDONLY);
430
google::protobuf::io::ZeroCopyInputStream* input=
431
new google::protobuf::io::FileInputStream(fd);
433
if (table->ParseFromZeroCopyStream(input) == false)
445
class StorageEngineGetTableProto: public unary_function<StorageEngine *,bool>
448
drizzled::message::Table *table_proto;
451
StorageEngineGetTableProto(const char* path_arg,
452
drizzled::message::Table *table_proto_arg,
454
:path(path_arg), table_proto(table_proto_arg), err(err_arg) {}
456
result_type operator() (argument_type engine)
458
int ret= engine->getTableProtoImplementation(path, table_proto);
301
460
if (ret != ENOENT)
304
return err == EEXIST || err != ENOENT;
308
class StorageEngineDoesTableExist: public unary_function<StorageEngine *, bool>
311
TableIdentifier &identifier;
314
StorageEngineDoesTableExist(Session& session_arg, TableIdentifier &identifier_arg) :
315
session(session_arg),
316
identifier(identifier_arg)
319
result_type operator() (argument_type engine)
321
return engine->doDoesTableExist(session, identifier);
326
Utility method which hides some of the details of getTableDefinition()
328
bool plugin::StorageEngine::doesTableExist(Session &session,
329
TableIdentifier &identifier,
330
bool include_temporary_tables)
332
if (include_temporary_tables)
334
if (session.doDoesTableExist(identifier))
338
EngineVector::iterator iter=
339
find_if(vector_of_engines.begin(), vector_of_engines.end(),
340
StorageEngineDoesTableExist(session, identifier));
342
if (iter == vector_of_engines.end())
350
bool plugin::StorageEngine::doDoesTableExist(Session&, TableIdentifier&)
352
cerr << " Engine was called for doDoesTableExist() and does not implement it: " << this->getName() << "\n";
358
Call this function in order to give the Cursor the possiblity
463
return *err == EEXIST;
468
Call this function in order to give the handler the possiblity
359
469
to ask engine if there are any new tables that should be written to disk
360
470
or any dropped tables that need to be removed from disk
362
int StorageEngine::getTableDefinition(Session& session,
363
TableIdentifier &identifier,
364
message::Table &table_message,
365
bool include_temporary_tables)
472
int StorageEngine::getTableProto(const char* path,
473
drizzled::message::Table *table_proto)
369
if (include_temporary_tables)
371
if (session.doGetTableDefinition(identifier, table_message) == EEXIST)
375
EngineVector::iterator iter=
376
find_if(vector_of_engines.begin(), vector_of_engines.end(),
377
StorageEngineGetTableDefinition(session, identifier, table_message, err));
379
if (iter == vector_of_engines.end())
477
drizzled::Registry<StorageEngine *>::iterator iter=
478
find_if(all_engines.begin(), all_engines.end(),
479
StorageEngineGetTableProto(path, table_proto, &err));
480
if (iter == all_engines.end())
482
string proto_path(path);
483
string file_ext(".dfe");
484
proto_path.append(file_ext);
486
int error= access(proto_path.c_str(), F_OK);
495
int read_proto_err= drizzle_read_table_proto(proto_path.c_str(),
507
int StorageEngine::renameTableImplementation(Session *, const char *from, const char *to)
510
for (const char **ext= bas_ext(); *ext ; ext++)
512
if (rename_file_ext(from, to, *ext))
514
if ((error=my_errno) != ENOENT)
524
Delete all files with extension from bas_ext().
526
@param name Base name of table
529
We assume that the handler may return more extensions than
530
was actually used for the file.
533
0 If we successfully deleted at least one file from base_ext and
534
didn't get any other errors than ENOENT
538
int StorageEngine::deleteTableImplementation(Session *, const std::string table_path)
541
int enoent_or_zero= ENOENT; // Error if no file was deleted
542
char buff[FN_REFLEN];
544
for (const char **ext=bas_ext(); *ext ; ext++)
546
fn_format(buff, table_path.c_str(), "", *ext,
547
MY_UNPACK_FILENAME|MY_APPEND_EXT);
548
if (my_delete_with_symlink(buff, MYF(0)))
550
if ((error= my_errno) != ENOENT)
554
enoent_or_zero= 0; // No error for ENOENT
555
error= enoent_or_zero;
388
561
An interceptor to hijack the text of the error message without
389
562
setting an error in the thread. We need the text to present it
591
class DeleteTableStorageEngine
592
: public unary_function<StorageEngine *, void>
599
DeleteTableStorageEngine(Session *session_arg, const char *path_arg,
600
handler **file_arg, int *error_arg)
601
: session(session_arg), path(path_arg), file(file_arg), dt_error(error_arg) {}
603
result_type operator() (argument_type engine)
605
char tmp_path[FN_REFLEN];
608
if(*dt_error!=ENOENT) /* already deleted table */
614
if (!engine->is_enabled())
617
if ((tmp_file= engine->create(NULL, session->mem_root)))
622
path= engine->checkLowercaseNames(path, tmp_path);
623
const std::string table_path(path);
624
int tmp_error= engine->deleteTable(session, table_path);
626
if (tmp_error != ENOENT)
630
if (engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY))
631
delete_table_proto_file(path);
633
tmp_error= delete_table_proto_file(path);
636
*dt_error= tmp_error;
418
returns ENOENT if the file doesn't exists.
650
This should return ENOENT if the file doesn't exists.
651
The .frm file will be deleted only if we return 0 or ENOENT
420
int StorageEngine::dropTable(Session& session,
421
TableIdentifier &identifier)
425
message::Table src_proto;
426
StorageEngine *engine;
428
error_proto= StorageEngine::getTableDefinition(session, identifier, src_proto);
430
if (error_proto == ER_CORRUPT_TABLE_DEFINITION)
432
string error_message;
434
error_message.append(identifier.getSQLPath());
435
error_message.append(" : ");
436
error_message.append(src_proto.InitializationErrorString());
438
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), error_message.c_str());
440
return ER_CORRUPT_TABLE_DEFINITION;
443
engine= StorageEngine::findByName(session, src_proto.engine().name());
447
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0), identifier.getSQLPath().c_str());
449
return ER_CORRUPT_TABLE_DEFINITION;
452
error= StorageEngine::dropTable(session, *engine, identifier);
454
if (error_proto && error == 0)
460
int StorageEngine::dropTable(Session& session,
461
StorageEngine &engine,
462
TableIdentifier &identifier)
466
engine.setTransactionReadWrite(session);
467
error= engine.doDropTable(session, identifier);
653
int ha_delete_table(Session *session, const char *path,
654
const char *db, const char *alias, bool generate_warning)
656
TableShare dummy_share;
658
memset(&dummy_table, 0, sizeof(dummy_table));
659
memset(&dummy_share, 0, sizeof(dummy_share));
661
dummy_table.s= &dummy_share;
666
for_each(all_engines.begin(), all_engines.end(),
667
DeleteTableStorageEngine(session, path, &file, &error));
669
if (error == ENOENT) /* proto may be left behind */
670
error= delete_table_proto_file(path);
672
if (error && generate_warning)
675
Because file->print_error() use my_error() to generate the error message
676
we use an internal error handler to intercept it and store the text
677
in a temporary buffer. Later the message will be presented to user
680
Ha_delete_table_error_handler ha_delete_table_error_handler;
682
/* Fill up strucutures that print_error may need */
683
dummy_share.path.str= (char*) path;
684
dummy_share.path.length= strlen(path);
685
dummy_share.db.str= (char*) db;
686
dummy_share.db.length= strlen(db);
687
dummy_share.table_name.str= (char*) alias;
688
dummy_share.table_name.length= strlen(alias);
689
dummy_table.alias= alias;
694
file->change_table_ptr(&dummy_table, &dummy_share);
696
session->push_internal_handler(&ha_delete_table_error_handler);
697
file->print_error(error, 0);
699
session->pop_internal_handler();
702
error= -1; /* General form of fail. maybe bad FRM */
705
XXX: should we convert *all* errors to warnings here?
706
What if the error is fatal?
708
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
709
ha_delete_table_error_handler.buff);
474
719
Initiates table-file and calls appropriate database-creator.
481
int StorageEngine::createTable(Session &session,
482
TableIdentifier &identifier,
483
bool update_create_info,
484
message::Table& table_message)
726
int ha_create_table(Session *session, const char *path,
727
const char *db, const char *table_name,
728
HA_CREATE_INFO *create_info,
729
bool update_create_info,
730
drizzled::message::Table *table_proto)
488
TableShare share(identifier.getSchemaName().c_str(), 0, identifier.getTableName().c_str(), identifier.getPath().c_str());
489
message::Table tmp_proto;
734
TableShare share(db, 0, table_name, path);
491
if (parse_table_proto(session, table_message, &share) || open_table_from_share(&session, &share, "", 0, 0, &table))
493
// @note Error occured, we should probably do a little more here.
738
if (parse_table_proto(session, *table_proto, &share))
497
if (update_create_info)
498
table.updateCreateInfo(&table_message);
500
/* Check for legal operations against the Engine using the proto (if used) */
501
if (table_message.type() == message::Table::TEMPORARY &&
502
share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
504
error= HA_ERR_UNSUPPORTED;
506
else if (table_message.type() != message::Table::TEMPORARY &&
507
share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
509
error= HA_ERR_UNSUPPORTED;
513
share.storage_engine->setTransactionReadWrite(session);
515
error= share.storage_engine->doCreateTable(session,
523
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), identifier.getSQLPath().c_str(), error);
526
table.closefrm(false);
743
if (open_table_def(session, &share))
747
if (open_table_from_share(session, &share, "", 0, (uint32_t) READ_ALL, 0,
751
if (update_create_info)
752
table.updateCreateInfo(create_info);
754
error= share.storage_engine->createTable(session, path, &table,
755
create_info, table_proto);
756
table.closefrm(false);
759
char name_buff[FN_REFLEN];
760
sprintf(name_buff,"%s.%s",db,table_name);
761
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
529
764
share.free_table_share();
530
765
return(error != 0);
533
Cursor *StorageEngine::getCursor(TableShare &share, memory::Root *alloc)
535
return create(share, alloc);
539
public unary_function<StorageEngine *, void>
541
CachedDirectory &directory;
542
SchemaIdentifier &identifier;
543
TableNameList &set_of_names;
547
AddTableName(CachedDirectory &directory_arg, SchemaIdentifier &identifier_arg, set<string>& of_names) :
548
directory(directory_arg),
549
identifier(identifier_arg),
550
set_of_names(of_names)
554
result_type operator() (argument_type engine)
556
engine->doGetTableNames(directory, identifier, set_of_names);
560
class AddTableIdentifier :
561
public unary_function<StorageEngine *, void>
563
CachedDirectory &directory;
564
SchemaIdentifier &identifier;
565
TableIdentifiers &set_of_identifiers;
569
AddTableIdentifier(CachedDirectory &directory_arg, SchemaIdentifier &identifier_arg, TableIdentifiers &of_names) :
570
directory(directory_arg),
571
identifier(identifier_arg),
572
set_of_identifiers(of_names)
576
result_type operator() (argument_type engine)
578
engine->doGetTableIdentifiers(directory, identifier, set_of_identifiers);
583
static SchemaIdentifier INFORMATION_SCHEMA_IDENTIFIER("information_schema");
584
static SchemaIdentifier DATA_DICTIONARY_IDENTIFIER("data_dictionary");
586
void StorageEngine::getTableNames(Session &session, SchemaIdentifier &schema_identifier, TableNameList &set_of_names)
588
CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
590
if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
592
else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
596
if (directory.fail())
598
errno= directory.getError();
600
my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), schema_identifier.getSQLPath().c_str());
602
my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
607
for_each(vector_of_engines.begin(), vector_of_engines.end(),
608
AddTableName(directory, schema_identifier, set_of_names));
610
session.doGetTableNames(directory, schema_identifier, set_of_names);
613
void StorageEngine::getTableIdentifiers(Session &session, SchemaIdentifier &schema_identifier, TableIdentifiers &set_of_identifiers)
615
CachedDirectory directory(schema_identifier.getPath(), set_of_table_definition_ext);
617
if (schema_identifier == INFORMATION_SCHEMA_IDENTIFIER)
619
else if (schema_identifier == DATA_DICTIONARY_IDENTIFIER)
623
if (directory.fail())
625
errno= directory.getError();
627
my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), schema_identifier.getSQLPath().c_str());
629
my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
634
for_each(vector_of_engines.begin(), vector_of_engines.end(),
635
AddTableIdentifier(directory, schema_identifier, set_of_identifiers));
637
session.doGetTableIdentifiers(directory, schema_identifier, set_of_identifiers);
640
/* This will later be converted to TableIdentifiers */
641
class DropTables: public unary_function<StorageEngine *, void>
644
TableIdentifierList &table_identifiers;
648
DropTables(Session &session_arg, TableIdentifierList &table_identifiers_arg) :
649
session(session_arg),
650
table_identifiers(table_identifiers_arg)
653
result_type operator() (argument_type engine)
655
for (TableIdentifierList::iterator iter= table_identifiers.begin();
656
iter != table_identifiers.end();
659
int error= engine->doDropTable(session, const_cast<TableIdentifier&>(*iter));
661
// On a return of zero we know we found and deleted the table. So we
662
// remove it from our search.
664
table_identifiers.erase(iter);
670
This only works for engines which use file based DFE.
672
Note-> Unlike MySQL, we do not, on purpose, delete files that do not match any engines.
674
void StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
676
CachedDirectory dir(directory, set_of_table_definition_ext);
677
TableIdentifierList table_identifiers;
681
errno= dir.getError();
682
my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
687
CachedDirectory::Entries files= dir.getEntries();
689
for (CachedDirectory::Entries::iterator fileIter= files.begin();
690
fileIter != files.end(); fileIter++)
694
CachedDirectory::Entry *entry= *fileIter;
696
/* We remove the file extension. */
697
length= entry->filename.length();
698
entry->filename.resize(length - DEFAULT_DEFINITION_FILE_EXT.length());
702
path+= entry->filename;
703
message::Table definition;
704
if (StorageEngine::readTableFile(path, definition))
706
TableIdentifier identifier(definition.schema(), definition.name(), path);
707
table_identifiers.push_back(identifier);
711
for_each(vector_of_engines.begin(), vector_of_engines.end(),
712
DropTables(session, table_identifiers));
769
const string ha_resolve_storage_engine_name(const StorageEngine *engine)
771
return engine == NULL ? string("UNKNOWN") : engine->getName();
774
const char *StorageEngine::checkLowercaseNames(const char *path, char *tmp_path)
776
if (flags.test(HTON_BIT_FILE_BASED))
779
/* Ensure that table handler get path in lower case */
780
if (tmp_path != path)
781
strcpy(tmp_path, path);
715
Now we just clean up anything that might left over.
717
We rescan because some of what might have been there should
718
now be all nice and cleaned up.
784
we only should turn into lowercase database/table part
785
so start the process after homedirectory
720
set<string> all_exts= set_of_table_definition_ext;
722
for (EngineVector::iterator iter= vector_of_engines.begin();
723
iter != vector_of_engines.end() ; iter++)
725
for (const char **ext= (*iter)->bas_ext(); *ext ; ext++)
726
all_exts.insert(*ext);
729
CachedDirectory rescan(directory, all_exts);
731
files= rescan.getEntries();
732
for (CachedDirectory::Entries::iterator fileIter= files.begin();
733
fileIter != files.end(); fileIter++)
736
CachedDirectory::Entry *entry= *fileIter;
740
path+= entry->filename;
742
unlink(path.c_str());
748
Print error that we got from Cursor function.
751
In case of delete table it's only safe to use the following parts of
752
the 'table' structure:
756
void StorageEngine::print_error(int error, myf errflag, Table &table)
758
print_error(error, errflag, &table);
761
void StorageEngine::print_error(int error, myf errflag, Table *table)
763
int textno= ER_GET_ERRNO;
766
textno=ER_OPEN_AS_READONLY;
772
textno=ER_FILE_NOT_FOUND;
774
case HA_ERR_KEY_NOT_FOUND:
775
case HA_ERR_NO_ACTIVE_RECORD:
776
case HA_ERR_END_OF_FILE:
777
textno=ER_KEY_NOT_FOUND;
779
case HA_ERR_WRONG_MRG_TABLE_DEF:
780
textno=ER_WRONG_MRG_TABLE;
782
case HA_ERR_FOUND_DUPP_KEY:
785
uint32_t key_nr= table->get_dup_key(error);
786
if ((int) key_nr >= 0)
788
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
791
(table->key_info[0].key_part[0].field->flags &
793
&& (current_session)->lex->sql_command == SQLCOM_ALTER_TABLE)
795
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
798
print_keydup_error(key_nr, err_msg, *table);
804
case HA_ERR_FOREIGN_DUPLICATE_KEY:
807
uint32_t key_nr= table->get_dup_key(error);
808
if ((int) key_nr >= 0)
812
/* Write the key in the error message */
813
char key[MAX_KEY_LENGTH];
814
String str(key,sizeof(key),system_charset_info);
816
/* Table is opened and defined at this point */
817
key_unpack(&str,table,(uint32_t) key_nr);
818
max_length= (DRIZZLE_ERRMSG_SIZE-
819
(uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
820
if (str.length() >= max_length)
822
str.length(max_length-4);
823
str.append(STRING_WITH_LEN("..."));
825
my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table->s->table_name.str,
826
str.c_ptr(), key_nr+1);
832
case HA_ERR_FOUND_DUPP_UNIQUE:
833
textno=ER_DUP_UNIQUE;
835
case HA_ERR_RECORD_CHANGED:
839
textno=ER_NOT_KEYFILE;
841
case HA_ERR_WRONG_IN_RECORD:
842
textno= ER_CRASHED_ON_USAGE;
844
case HA_ERR_CRASHED_ON_USAGE:
845
textno=ER_CRASHED_ON_USAGE;
847
case HA_ERR_NOT_A_TABLE:
850
case HA_ERR_CRASHED_ON_REPAIR:
851
textno=ER_CRASHED_ON_REPAIR;
853
case HA_ERR_OUT_OF_MEM:
854
textno=ER_OUT_OF_RESOURCES;
856
case HA_ERR_WRONG_COMMAND:
857
textno=ER_ILLEGAL_HA;
859
case HA_ERR_OLD_FILE:
860
textno=ER_OLD_KEYFILE;
862
case HA_ERR_UNSUPPORTED:
863
textno=ER_UNSUPPORTED_EXTENSION;
865
case HA_ERR_RECORD_FILE_FULL:
866
case HA_ERR_INDEX_FILE_FULL:
867
textno=ER_RECORD_FILE_FULL;
869
case HA_ERR_LOCK_WAIT_TIMEOUT:
870
textno=ER_LOCK_WAIT_TIMEOUT;
872
case HA_ERR_LOCK_TABLE_FULL:
873
textno=ER_LOCK_TABLE_FULL;
875
case HA_ERR_LOCK_DEADLOCK:
876
textno=ER_LOCK_DEADLOCK;
878
case HA_ERR_READ_ONLY_TRANSACTION:
879
textno=ER_READ_ONLY_TRANSACTION;
881
case HA_ERR_CANNOT_ADD_FOREIGN:
882
textno=ER_CANNOT_ADD_FOREIGN;
884
case HA_ERR_ROW_IS_REFERENCED:
887
get_error_message(error, &str);
888
my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
891
case HA_ERR_NO_REFERENCED_ROW:
894
get_error_message(error, &str);
895
my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
898
case HA_ERR_TABLE_DEF_CHANGED:
899
textno=ER_TABLE_DEF_CHANGED;
901
case HA_ERR_NO_SUCH_TABLE:
903
my_error(ER_NO_SUCH_TABLE, MYF(0), table->s->getSchemaName(),
904
table->s->table_name.str);
906
case HA_ERR_RBR_LOGGING_FAILED:
907
textno= ER_BINLOG_ROW_LOGGING_FAILED;
909
case HA_ERR_DROP_INDEX_FK:
912
const char *ptr= "???";
913
uint32_t key_nr= table->get_dup_key(error);
914
if ((int) key_nr >= 0)
915
ptr= table->key_info[key_nr].name;
916
my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
919
case HA_ERR_TABLE_NEEDS_UPGRADE:
920
textno=ER_TABLE_NEEDS_UPGRADE;
922
case HA_ERR_TABLE_READONLY:
923
textno= ER_OPEN_AS_READONLY;
925
case HA_ERR_AUTOINC_READ_FAILED:
926
textno= ER_AUTOINC_READ_FAILED;
928
case HA_ERR_AUTOINC_ERANGE:
929
textno= ER_WARN_DATA_OUT_OF_RANGE;
931
case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
932
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
933
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
938
The error was "unknown" to this function.
939
Ask Cursor if it has got a message for this error
941
bool temporary= false;
943
temporary= get_error_message(error, &str);
946
const char* engine_name= getName().c_str();
948
my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(),
951
my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
955
my_error(ER_GET_ERRNO,errflag,error);
960
my_error(textno, errflag, table->s->table_name.str, error);
965
Return an error message specific to this Cursor.
967
@param error error code previously returned by Cursor
968
@param buf pointer to String where to add error message
971
Returns true if this is a temporary error
973
bool StorageEngine::get_error_message(int , String* )
979
void StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, Table &table)
981
/* Write the duplicated key in the error message */
982
char key[MAX_KEY_LENGTH];
983
String str(key,sizeof(key),system_charset_info);
985
if (key_nr == MAX_KEY)
988
str.copy("", 0, system_charset_info);
989
my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
787
if (strstr(tmp_path, drizzle_tmpdir) == tmp_path)
788
my_casedn_str(files_charset_info, tmp_path + strlen(drizzle_tmpdir));
993
/* Table is opened and defined at this point */
994
key_unpack(&str, &table, (uint32_t) key_nr);
995
uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
996
if (str.length() >= max_length)
998
str.length(max_length-4);
999
str.append(STRING_WITH_LEN("..."));
1001
my_printf_error(ER_DUP_ENTRY, msg,
1002
MYF(0), str.c_ptr(), table.key_info[key_nr].name);
1007
int StorageEngine::deleteDefinitionFromPath(TableIdentifier &identifier)
1009
string path(identifier.getPath());
1011
path.append(DEFAULT_DEFINITION_FILE_EXT);
1013
return internal::my_delete(path.c_str(), MYF(0));
1016
int StorageEngine::renameDefinitionFromPath(TableIdentifier &dest, TableIdentifier &src)
1018
message::Table table_message;
1019
string src_path(src.getPath());
1020
string dest_path(dest.getPath());
1022
src_path.append(DEFAULT_DEFINITION_FILE_EXT);
1023
dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
1025
bool was_read= StorageEngine::readTableFile(src_path.c_str(), table_message);
1032
dest.copyToTableMessage(table_message);
1034
int error= StorageEngine::writeDefinitionFromPath(dest, table_message);
1038
if (unlink(src_path.c_str()))
1039
perror(src_path.c_str());
1045
int StorageEngine::writeDefinitionFromPath(TableIdentifier &identifier, message::Table &table_message)
1047
char definition_file_tmp[FN_REFLEN];
1048
string file_name(identifier.getPath());
1050
file_name.append(DEFAULT_DEFINITION_FILE_EXT);
1052
snprintf(definition_file_tmp, sizeof(definition_file_tmp), "%sXXXXXX", file_name.c_str());
1054
int fd= mkstemp(definition_file_tmp);
1058
perror(definition_file_tmp);
1062
google::protobuf::io::ZeroCopyOutputStream* output=
1063
new google::protobuf::io::FileOutputStream(fd);
1065
if (not table_message.SerializeToZeroCopyStream(output))
1067
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1068
table_message.InitializationErrorString().c_str());
1071
if (close(fd) == -1)
1072
perror(definition_file_tmp);
1074
if (unlink(definition_file_tmp) == -1)
1075
perror(definition_file_tmp);
1077
return ER_CORRUPT_TABLE_DEFINITION;
1082
if (close(fd) == -1)
1085
perror(definition_file_tmp);
1087
if (unlink(definition_file_tmp))
1088
perror(definition_file_tmp);
1093
if (rename(definition_file_tmp, file_name.c_str()) == -1)
1096
perror(definition_file_tmp);
1098
if (unlink(definition_file_tmp))
1099
perror(definition_file_tmp);
1107
class CanCreateTable: public unary_function<StorageEngine *, bool>
1109
TableIdentifier &identifier;
790
my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
795
class DFETableNameIterator: public TableNameIteratorImplementation
799
uint32_t current_entry;
1112
CanCreateTable(TableIdentifier &identifier_arg) :
1113
identifier(identifier_arg)
1116
result_type operator() (argument_type engine)
1118
return not engine->doCanCreateTable(identifier);
802
DFETableNameIterator(const std::string &database)
803
: TableNameIteratorImplementation(database),
808
~DFETableNameIterator();
810
int next(std::string *name);
1124
@note on success table can be created.
1126
bool StorageEngine::canCreateTable(drizzled::TableIdentifier &identifier)
1128
EngineVector::iterator iter=
1129
find_if(vector_of_engines.begin(), vector_of_engines.end(),
1130
CanCreateTable(identifier));
1132
if (iter == vector_of_engines.end())
1140
bool StorageEngine::readTableFile(const std::string &path, message::Table &table_message)
1142
fstream input(path.c_str(), ios::in | ios::binary);
1146
if (table_message.ParseFromIstream(&input))
1151
my_error(ER_CORRUPT_TABLE_DEFINITION, MYF(0),
1152
table_message.InitializationErrorString().c_str());
1156
perror(path.c_str());
1164
} /* namespace plugin */
1165
} /* namespace drizzled */
814
DFETableNameIterator::~DFETableNameIterator()
820
int DFETableNameIterator::next(string *name)
822
char uname[NAME_LEN + 1];
825
uint32_t file_name_len;
826
const char *wild= NULL;
831
char path[FN_REFLEN];
833
build_table_filename(path, sizeof(path), db.c_str(), "", false);
835
dirp = my_dir(path,MYF(dir ? MY_WANT_STAT : 0));
839
if (my_errno == ENOENT)
840
my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db.c_str());
842
my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), path, my_errno);
852
if (current_entry == dirp->number_off_files)
859
file= dirp->dir_entry + current_entry;
861
if (my_strcasecmp(system_charset_info, ext=fn_rext(file->name),".dfe") ||
862
is_prefix(file->name, TMP_FILE_PREFIX))
866
file_name_len= filename_to_tablename(file->name, uname, sizeof(uname));
868
uname[file_name_len]= '\0';
870
if (wild && wild_compare(uname, wild, 0))
880
TableNameIterator::TableNameIterator(const std::string &db)
881
: current_implementation(NULL), database(db)
883
engine_iter= all_engines.begin();
884
default_implementation= new DFETableNameIterator(database);
887
TableNameIterator::~TableNameIterator()
889
delete current_implementation;
892
int TableNameIterator::next(std::string *name)
897
if (current_implementation == NULL)
899
while(current_implementation == NULL && engine_iter != all_engines.end())
901
StorageEngine *engine= *engine_iter;
902
current_implementation= engine->tableNameIterator(database);
906
if (current_implementation == NULL && engine_iter == all_engines.end())
908
current_implementation= default_implementation;
912
err= current_implementation->next(name);
916
if (current_implementation != default_implementation)
918
delete current_implementation;
919
current_implementation= NULL;