1
/* -*- mode: c++; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2008 Sun Microsystems
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; version 2 of the License.
10
* This program is distributed in the hope that it will be useful,
11
* but WITHOUT ANY WARRANTY; without even the implied warranty of
12
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
* GNU General Public License for more details.
15
* You should have received a copy of the GNU General Public License
16
* along with this program; if not, write to the Free Software
17
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
31
#include <google/protobuf/io/zero_copy_stream.h>
32
#include <google/protobuf/io/zero_copy_stream_impl.h>
34
#include "drizzled/internal/my_dir.h"
35
#include "drizzled/my_hash.h"
36
#include "drizzled/cached_directory.h"
38
#include <drizzled/definitions.h>
39
#include <drizzled/base.h>
40
#include <drizzled/cursor.h>
41
#include <drizzled/plugin/storage_engine.h>
42
#include <drizzled/session.h>
43
#include <drizzled/error.h>
44
#include <drizzled/gettext.h>
45
#include <drizzled/unireg.h>
46
#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/internal/my_sys.h"
54
#include <drizzled/table_proto.h>
56
#include "drizzled/hash.h"
58
static bool shutdown_has_begun= false; // Once we put in the container for the vector/etc for engines this will go away.
65
typedef hash_map<std::string, plugin::StorageEngine *> EngineMap;
66
typedef std::vector<plugin::StorageEngine *> EngineVector;
68
static EngineVector vector_of_engines;
69
static EngineVector vector_of_transactional_engines;
71
const std::string plugin::UNKNOWN_STRING("UNKNOWN");
72
const std::string plugin::DEFAULT_DEFINITION_FILE_EXT(".dfe");
74
static std::set<std::string> set_of_table_definition_ext;
76
plugin::StorageEngine::StorageEngine(const string name_arg,
77
const bitset<HTON_BIT_SIZE> &flags_arg,
78
size_t savepoint_offset_arg,
80
: Plugin(name_arg, "StorageEngine"),
81
two_phase_commit(support_2pc),
84
savepoint_offset(savepoint_alloc_size),
85
orig_savepoint_offset(savepoint_offset_arg),
90
savepoint_alloc_size+= orig_savepoint_offset;
95
pthread_mutex_init(&proto_cache_mutex, NULL);
99
plugin::StorageEngine::~StorageEngine()
101
savepoint_alloc_size-= orig_savepoint_offset;
102
pthread_mutex_destroy(&proto_cache_mutex);
105
void plugin::StorageEngine::setTransactionReadWrite(Session& session)
107
Ha_trx_info *ha_info= session.getEngineInfo(this);
110
When a storage engine method is called, the transaction must
111
have been started, unless it's a DDL call, for which the
112
storage engine starts the transaction internally, and commits
113
it internally, without registering in the ha_list.
114
Unfortunately here we can't know know for sure if the engine
115
has registered the transaction or not, so we must check.
117
if (ha_info->is_started())
120
* table_share can be NULL in plugin::StorageEngine::dropTable().
122
ha_info->set_trx_read_write();
128
int plugin::StorageEngine::doRenameTable(Session *,
133
for (const char **ext= bas_ext(); *ext ; ext++)
135
if (rename_file_ext(from, to, *ext))
137
if ((error=errno) != ENOENT)
147
Delete all files with extension from bas_ext().
149
@param name Base name of table
152
We assume that the Cursor may return more extensions than
153
was actually used for the file.
156
0 If we successfully deleted at least one file from base_ext and
157
didn't get any other errors than ENOENT
161
int plugin::StorageEngine::doDropTable(Session&,
162
const string table_path)
165
int enoent_or_zero= ENOENT; // Error if no file was deleted
166
char buff[FN_REFLEN];
168
for (const char **ext= bas_ext(); *ext ; ext++)
170
fn_format(buff, table_path.c_str(), "", *ext,
171
MY_UNPACK_FILENAME|MY_APPEND_EXT);
172
if (my_delete_with_symlink(buff, MYF(0)))
174
if ((error= errno) != ENOENT)
178
enoent_or_zero= 0; // No error for ENOENT
179
error= enoent_or_zero;
184
const char *plugin::StorageEngine::checkLowercaseNames(const char *path,
187
if (flags.test(HTON_BIT_FILE_BASED))
190
/* Ensure that table Cursor get path in lower case */
191
if (tmp_path != path)
192
strcpy(tmp_path, path);
195
we only should turn into lowercase database/table part
196
so start the process after homedirectory
198
if (strstr(tmp_path, drizzle_tmpdir) == tmp_path)
199
my_casedn_str(files_charset_info, tmp_path + strlen(drizzle_tmpdir));
201
my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
207
bool plugin::StorageEngine::addPlugin(plugin::StorageEngine *engine)
210
vector_of_engines.push_back(engine);
212
if (engine->check_flag(HTON_BIT_DOES_TRANSACTIONS))
213
vector_of_transactional_engines.push_back(engine);
215
if (engine->getTableDefinitionFileExtension().length())
217
assert(engine->getTableDefinitionFileExtension().length() == DEFAULT_DEFINITION_FILE_EXT.length());
218
set_of_table_definition_ext.insert(engine->getTableDefinitionFileExtension());
224
void plugin::StorageEngine::removePlugin(plugin::StorageEngine *)
226
if (shutdown_has_begun == false)
228
vector_of_engines.clear();
229
vector_of_transactional_engines.clear();
231
shutdown_has_begun= true;
235
class FindEngineByName
236
: public unary_function<plugin::StorageEngine *, bool>
240
explicit FindEngineByName(const string target_arg)
243
result_type operator() (argument_type engine)
245
string engine_name(engine->getName());
247
transform(engine_name.begin(), engine_name.end(),
248
engine_name.begin(), ::tolower);
249
return engine_name == target;
253
plugin::StorageEngine *plugin::StorageEngine::findByName(string find_str)
255
transform(find_str.begin(), find_str.end(),
256
find_str.begin(), ::tolower);
259
EngineVector::iterator iter= find_if(vector_of_engines.begin(),
260
vector_of_engines.end(),
261
FindEngineByName(find_str));
262
if (iter != vector_of_engines.end())
264
StorageEngine *engine= *iter;
265
if (engine->is_user_selectable())
272
plugin::StorageEngine *plugin::StorageEngine::findByName(Session& session,
276
transform(find_str.begin(), find_str.end(),
277
find_str.begin(), ::tolower);
279
if (find_str.compare("default") == 0)
280
return session.getDefaultStorageEngine();
282
EngineVector::iterator iter= find_if(vector_of_engines.begin(),
283
vector_of_engines.end(),
284
FindEngineByName(find_str));
285
if (iter != vector_of_engines.end())
287
StorageEngine *engine= *iter;
288
if (engine->is_user_selectable())
295
class StorageEngineCloseConnection
296
: public unary_function<plugin::StorageEngine *, void>
300
StorageEngineCloseConnection(Session *session_arg) : session(session_arg) {}
302
there's no need to rollback here as all transactions must
303
be rolled back already
305
inline result_type operator() (argument_type engine)
307
if (engine->is_enabled() && (*session->getEngineData(engine)))
308
engine->close_connection(session);
314
don't bother to rollback here, it's done already
316
void plugin::StorageEngine::closeConnection(Session* session)
318
for_each(vector_of_engines.begin(), vector_of_engines.end(),
319
StorageEngineCloseConnection(session));
322
void plugin::StorageEngine::dropDatabase(char* path)
324
for_each(vector_of_engines.begin(), vector_of_engines.end(),
325
bind2nd(mem_fun(&plugin::StorageEngine::drop_database),path));
328
int plugin::StorageEngine::commitOrRollbackByXID(XID *xid, bool commit)
333
transform(vector_of_engines.begin(), vector_of_engines.end(), results.begin(),
334
bind2nd(mem_fun(&plugin::StorageEngine::commit_by_xid),xid));
336
transform(vector_of_engines.begin(), vector_of_engines.end(), results.begin(),
337
bind2nd(mem_fun(&plugin::StorageEngine::rollback_by_xid),xid));
339
if (find_if(results.begin(), results.end(), bind2nd(equal_to<int>(),0))
347
This function should be called when MySQL sends rows of a SELECT result set
348
or the EOF mark to the client. It releases a possible adaptive hash index
349
S-latch held by session in InnoDB and also releases a possible InnoDB query
350
FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
351
keep them over several calls of the InnoDB Cursor interface when a join
352
is executed. But when we let the control to pass to the client they have
353
to be released because if the application program uses mysql_use_result(),
354
it may deadlock on the S-latch if the application on another connection
355
performs another SQL query. In MySQL-4.1 this is even more important because
356
there a connection can have several SELECT queries open at the same time.
358
@param session the thread handle of the current connection
363
int plugin::StorageEngine::releaseTemporaryLatches(Session *session)
365
for_each(vector_of_transactional_engines.begin(), vector_of_transactional_engines.end(),
366
bind2nd(mem_fun(&plugin::StorageEngine::release_temporary_latches),session));
370
bool plugin::StorageEngine::flushLogs(plugin::StorageEngine *engine)
374
if (find_if(vector_of_engines.begin(), vector_of_engines.end(),
375
mem_fun(&plugin::StorageEngine::flush_logs))
376
!= vector_of_engines.begin())
381
if ((!engine->is_enabled()) ||
382
(engine->flush_logs()))
389
recover() step of xa.
392
there are three modes of operation:
393
- automatic recover after a crash
394
in this case commit_list != 0, tc_heuristic_recover==0
395
all xids from commit_list are committed, others are rolled back
396
- manual (heuristic) recover
397
in this case commit_list==0, tc_heuristic_recover != 0
398
DBA has explicitly specified that all prepared transactions should
399
be committed (or rolled back).
400
- no recovery (MySQL did not detect a crash)
401
in this case commit_list==0, tc_heuristic_recover == 0
402
there should be no prepared transactions in this case.
404
class XARecover : unary_function<plugin::StorageEngine *, void>
406
int trans_len, found_foreign_xids, found_my_xids;
412
XARecover(XID *trans_list_arg, int trans_len_arg,
413
HASH *commit_list_arg, bool dry_run_arg)
414
: trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
416
trans_list(trans_list_arg), commit_list(commit_list_arg),
422
return found_foreign_xids;
427
return found_my_xids;
430
result_type operator() (argument_type engine)
435
if (engine->is_enabled())
437
while ((got= engine->recover(trans_list, trans_len)) > 0 )
439
errmsg_printf(ERRMSG_LVL_INFO,
440
_("Found %d prepared transaction(s) in %s"),
441
got, engine->getName().c_str());
442
for (int i=0; i < got; i ++)
444
my_xid x=trans_list[i].get_my_xid();
445
if (!x) // not "mine" - that is generated by external TM
447
xid_cache_insert(trans_list+i, XA_PREPARED);
448
found_foreign_xids++;
458
hash_search(commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
459
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
461
engine->commit_by_xid(trans_list+i);
465
engine->rollback_by_xid(trans_list+i);
475
int plugin::StorageEngine::recover(HASH *commit_list)
477
XID *trans_list= NULL;
480
bool dry_run= (commit_list==0 && tc_heuristic_recover==0);
482
/* commit_list and tc_heuristic_recover cannot be set both */
483
assert(commit_list==0 || tc_heuristic_recover==0);
485
/* if either is set, total_ha_2pc must be set too */
486
if (total_ha_2pc <= 1)
490
#ifndef WILL_BE_DELETED_LATER
493
for now, only InnoDB supports 2pc. It means we can always safely
494
rollback all pending transactions, without risking inconsistent data
497
assert(total_ha_2pc == 2); // only InnoDB and binlog
498
tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
501
for (trans_len= MAX_XID_LIST_SIZE ;
502
trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
504
trans_list=(XID *)malloc(trans_len*sizeof(XID));
508
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
513
errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
516
XARecover recover_func(trans_list, trans_len, commit_list, dry_run);
517
for_each(vector_of_transactional_engines.begin(), vector_of_transactional_engines.end(),
521
if (recover_func.getForeignXIDs())
522
errmsg_printf(ERRMSG_LVL_WARN,
523
_("Found %d prepared XA transactions"),
524
recover_func.getForeignXIDs());
525
if (dry_run && recover_func.getMyXIDs())
527
errmsg_printf(ERRMSG_LVL_ERROR,
528
_("Found %d prepared transactions! It means that drizzled "
529
"was not shut down properly last time and critical "
530
"recovery information (last binlog or %s file) was "
531
"manually deleted after a crash. You have to start "
532
"drizzled with the --tc-heuristic-recover switch to "
533
"commit or rollback pending transactions."),
534
recover_func.getMyXIDs(), opt_tc_log_file);
538
errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
542
int plugin::StorageEngine::startConsistentSnapshot(Session *session)
544
for_each(vector_of_engines.begin(), vector_of_engines.end(),
545
bind2nd(mem_fun(&plugin::StorageEngine::start_consistent_snapshot),
550
class StorageEngineGetTableDefinition: public unary_function<plugin::StorageEngine *,bool>
555
const char *table_name;
557
message::Table *table_proto;
561
StorageEngineGetTableDefinition(Session& session_arg,
562
const char* path_arg,
564
const char *table_name_arg,
565
const bool is_tmp_arg,
566
message::Table *table_proto_arg,
568
session(session_arg),
571
table_name(table_name_arg),
573
table_proto(table_proto_arg),
576
result_type operator() (argument_type engine)
578
int ret= engine->doGetTableDefinition(session,
588
return *err == EEXIST;
592
static int drizzle_read_table_proto(const char* path, message::Table* table)
594
int fd= open(path, O_RDONLY);
599
google::protobuf::io::ZeroCopyInputStream* input=
600
new google::protobuf::io::FileInputStream(fd);
602
if (table->ParseFromZeroCopyStream(input) == false)
615
Call this function in order to give the Cursor the possiblity
616
to ask engine if there are any new tables that should be written to disk
617
or any dropped tables that need to be removed from disk
619
int plugin::StorageEngine::getTableDefinition(Session& session,
620
TableIdentifier &identifier,
621
message::Table *table_proto)
623
return getTableDefinition(session,
624
identifier.getPath(), identifier.getDBName(), identifier.getTableName(), identifier.isTmp(),
628
int plugin::StorageEngine::getTableDefinition(Session& session,
633
message::Table *table_proto)
637
vector<plugin::StorageEngine *>::iterator iter=
638
find_if(vector_of_engines.begin(), vector_of_engines.end(),
639
StorageEngineGetTableDefinition(session, path, NULL, NULL, true, table_proto, &err));
641
if (iter == vector_of_engines.end())
643
string proto_path(path);
644
string file_ext(".dfe");
645
proto_path.append(file_ext);
647
int error= access(proto_path.c_str(), F_OK);
656
int read_proto_err= drizzle_read_table_proto(proto_path.c_str(),
668
An interceptor to hijack the text of the error message without
669
setting an error in the thread. We need the text to present it
670
in the form of a warning to the user.
673
class Ha_delete_table_error_handler: public Internal_error_handler
676
Ha_delete_table_error_handler() : Internal_error_handler() {}
677
virtual bool handle_error(uint32_t sql_errno,
679
DRIZZLE_ERROR::enum_warning_level level,
681
char buff[DRIZZLE_ERRMSG_SIZE];
686
Ha_delete_table_error_handler::
687
handle_error(uint32_t ,
689
DRIZZLE_ERROR::enum_warning_level ,
692
/* Grab the error message */
693
strncpy(buff, message, sizeof(buff)-1);
699
This should return ENOENT if the file doesn't exists.
700
The .frm file will be deleted only if we return 0 or ENOENT
702
int plugin::StorageEngine::dropTable(Session& session,
703
TableIdentifier &identifier,
704
bool generate_warning)
708
message::Table src_proto;
709
plugin::StorageEngine* engine;
711
error_proto= plugin::StorageEngine::getTableDefinition(session,
715
engine= plugin::StorageEngine::findByName(session,
716
src_proto.engine().name());
720
engine->setTransactionReadWrite(session);
721
error= engine->doDropTable(session, identifier.getPath());
728
if (engine && engine->check_flag(HTON_BIT_HAS_DATA_DICTIONARY))
730
deleteDefinitionFromPath(identifier);
734
error= deleteDefinitionFromPath(identifier);
739
if (error_proto && error == 0)
742
if (error && generate_warning)
745
Because engine->print_error() use my_error() to generate the error message
746
we use an internal error Cursor to intercept it and store the text
747
in a temporary buffer. Later the message will be presented to user
750
Ha_delete_table_error_handler ha_delete_table_error_handler;
752
session.push_internal_handler(&ha_delete_table_error_handler);
753
engine->print_error(error, 0);
755
session.pop_internal_handler();
758
XXX: should we convert *all* errors to warnings here?
759
What if the error is fatal?
761
push_warning(&session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
762
ha_delete_table_error_handler.buff);
769
Initiates table-file and calls appropriate database-creator.
776
@todo refactor to remove goto
778
int plugin::StorageEngine::createTable(Session& session,
779
TableIdentifier &identifier,
780
bool update_create_info,
781
drizzled::message::Table& table_proto, bool proto_used)
785
TableShare share(identifier.getDBName(), 0, identifier.getTableName(), identifier.getPath());
786
message::Table tmp_proto;
790
if (parse_table_proto(session, table_proto, &share))
795
if (open_table_def(session, &share))
799
if (open_table_from_share(&session, &share, "", 0, (uint32_t) READ_ALL, 0,
803
if (update_create_info)
804
table.updateCreateInfo(&table_proto);
806
/* Check for legal operations against the Engine using the proto (if used) */
809
if (table_proto.type() == message::Table::TEMPORARY &&
810
share.storage_engine->check_flag(HTON_BIT_TEMPORARY_NOT_SUPPORTED) == true)
812
error= HA_ERR_UNSUPPORTED;
815
else if (table_proto.type() != message::Table::TEMPORARY &&
816
share.storage_engine->check_flag(HTON_BIT_TEMPORARY_ONLY) == true)
818
error= HA_ERR_UNSUPPORTED;
823
if (! share.storage_engine->is_enabled())
825
error= HA_ERR_UNSUPPORTED;
831
char name_buff[FN_REFLEN];
832
const char *table_name_arg;
834
table_name_arg= share.storage_engine->checkLowercaseNames(identifier.getPath(), name_buff);
836
share.storage_engine->setTransactionReadWrite(session);
838
error= share.storage_engine->doCreateTable(&session,
845
table.closefrm(false);
849
char name_buff[FN_REFLEN];
850
sprintf(name_buff,"%s.%s", identifier.getDBName(), identifier.getTableName());
851
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
854
share.free_table_share();
858
Cursor *plugin::StorageEngine::getCursor(TableShare &share, memory::Root *alloc)
861
return create(share, alloc);
865
TODO -> Remove this to force all engines to implement their own file. Solves the "we only looked at dfe" problem.
867
void plugin::StorageEngine::doGetTableNames(CachedDirectory &directory, string&, set<string>& set_of_names)
869
CachedDirectory::Entries entries= directory.getEntries();
871
for (CachedDirectory::Entries::iterator entry_iter= entries.begin();
872
entry_iter != entries.end(); ++entry_iter)
874
CachedDirectory::Entry *entry= *entry_iter;
875
string *filename= &entry->filename;
877
assert(filename->size());
879
const char *ext= strchr(filename->c_str(), '.');
881
if (ext == NULL || my_strcasecmp(system_charset_info, ext, DEFAULT_DEFINITION_FILE_EXT.c_str()) ||
882
(filename->compare(0, strlen(TMP_FILE_PREFIX), TMP_FILE_PREFIX) == 0))
886
char uname[NAME_LEN + 1];
887
uint32_t file_name_len;
889
file_name_len= filename_to_tablename(filename->c_str(), uname, sizeof(uname));
890
// TODO: Remove need for memory copy here
891
uname[file_name_len - sizeof(".dfe") + 1]= '\0'; // Subtract ending, place NULL
892
set_of_names.insert(uname);
898
public unary_function<plugin::StorageEngine *, void>
901
CachedDirectory& directory;
902
set<string>& set_of_names;
906
AddTableName(CachedDirectory& directory_arg, string& database_name, set<string>& of_names) :
907
directory(directory_arg),
908
set_of_names(of_names)
913
result_type operator() (argument_type engine)
915
engine->doGetTableNames(directory, db, set_of_names);
919
void plugin::StorageEngine::getTableNames(string& db, set<string>& set_of_names)
921
char tmp_path[FN_REFLEN];
923
build_table_filename(tmp_path, sizeof(tmp_path), db.c_str(), "", false);
925
CachedDirectory directory(tmp_path, set_of_table_definition_ext);
927
if (db.compare("information_schema"))
929
if (directory.fail())
931
errno= directory.getError();
933
my_error(ER_BAD_DB_ERROR, MYF(ME_BELL+ME_WAITTANG), db.c_str());
935
my_error(ER_CANT_READ_DIR, MYF(ME_BELL+ME_WAITTANG), directory.getPath(), errno);
940
for_each(vector_of_engines.begin(), vector_of_engines.end(),
941
AddTableName(directory, db, set_of_names));
944
/* This will later be converted to TableIdentifiers */
945
class DropTables: public unary_function<plugin::StorageEngine *, void>
948
set<string>& set_of_names;
952
DropTables(Session &session_arg, set<string>& of_names) :
953
session(session_arg),
954
set_of_names(of_names)
957
result_type operator() (argument_type engine)
960
for (set<string>::iterator iter= set_of_names.begin();
961
iter != set_of_names.end();
964
int error= engine->doDropTable(session, *iter);
966
// On a return of zero we know we found and deleted the table. So we
967
// remove it from our search.
969
set_of_names.erase(iter);
975
This only works for engines which use file based DFE.
977
Note-> Unlike MySQL, we do not, on purpose, delete files that do not match any engines.
979
void plugin::StorageEngine::removeLostTemporaryTables(Session &session, const char *directory)
981
CachedDirectory dir(directory, set_of_table_definition_ext);
982
set<string> set_of_table_names;
986
errno= dir.getError();
987
my_error(ER_CANT_READ_DIR, MYF(0), directory, errno);
992
CachedDirectory::Entries files= dir.getEntries();
994
for (CachedDirectory::Entries::iterator fileIter= files.begin();
995
fileIter != files.end(); fileIter++)
999
CachedDirectory::Entry *entry= *fileIter;
1001
/* We remove the file extension. */
1002
length= entry->filename.length();
1003
entry->filename.resize(length - DEFAULT_DEFINITION_FILE_EXT.length());
1007
path+= entry->filename;
1008
set_of_table_names.insert(path);
1011
for_each(vector_of_engines.begin(), vector_of_engines.end(),
1012
DropTables(session, set_of_table_names));
1015
Now we just clean up anything that might left over.
1017
We rescan because some of what might have been there should
1018
now be all nice and cleaned up.
1020
set<string> all_exts= set_of_table_definition_ext;
1022
for (vector<plugin::StorageEngine *>::iterator iter= vector_of_engines.begin();
1023
iter != vector_of_engines.end() ; iter++)
1025
for (const char **ext= (*iter)->bas_ext(); *ext ; ext++)
1026
all_exts.insert(*ext);
1029
CachedDirectory rescan(directory, all_exts);
1031
files= rescan.getEntries();
1032
for (CachedDirectory::Entries::iterator fileIter= files.begin();
1033
fileIter != files.end(); fileIter++)
1036
CachedDirectory::Entry *entry= *fileIter;
1040
path+= entry->filename;
1042
unlink(path.c_str());
1048
Print error that we got from Cursor function.
1051
In case of delete table it's only safe to use the following parts of
1052
the 'table' structure:
1056
void plugin::StorageEngine::print_error(int error, myf errflag, Table &table)
1058
print_error(error, errflag, &table);
1061
void plugin::StorageEngine::print_error(int error, myf errflag, Table *table)
1063
int textno= ER_GET_ERRNO;
1066
textno=ER_OPEN_AS_READONLY;
1069
textno=ER_FILE_USED;
1072
textno=ER_FILE_NOT_FOUND;
1074
case HA_ERR_KEY_NOT_FOUND:
1075
case HA_ERR_NO_ACTIVE_RECORD:
1076
case HA_ERR_END_OF_FILE:
1077
textno=ER_KEY_NOT_FOUND;
1079
case HA_ERR_WRONG_MRG_TABLE_DEF:
1080
textno=ER_WRONG_MRG_TABLE;
1082
case HA_ERR_FOUND_DUPP_KEY:
1085
uint32_t key_nr= table->get_dup_key(error);
1086
if ((int) key_nr >= 0)
1088
const char *err_msg= ER(ER_DUP_ENTRY_WITH_KEY_NAME);
1091
(table->key_info[0].key_part[0].field->flags &
1092
AUTO_INCREMENT_FLAG)
1093
&& (current_session)->lex->sql_command == SQLCOM_ALTER_TABLE)
1095
err_msg= ER(ER_DUP_ENTRY_AUTOINCREMENT_CASE);
1098
print_keydup_error(key_nr, err_msg, *table);
1104
case HA_ERR_FOREIGN_DUPLICATE_KEY:
1107
uint32_t key_nr= table->get_dup_key(error);
1108
if ((int) key_nr >= 0)
1110
uint32_t max_length;
1112
/* Write the key in the error message */
1113
char key[MAX_KEY_LENGTH];
1114
String str(key,sizeof(key),system_charset_info);
1116
/* Table is opened and defined at this point */
1117
key_unpack(&str,table,(uint32_t) key_nr);
1118
max_length= (DRIZZLE_ERRMSG_SIZE-
1119
(uint32_t) strlen(ER(ER_FOREIGN_DUPLICATE_KEY)));
1120
if (str.length() >= max_length)
1122
str.length(max_length-4);
1123
str.append(STRING_WITH_LEN("..."));
1125
my_error(ER_FOREIGN_DUPLICATE_KEY, MYF(0), table->s->table_name.str,
1126
str.c_ptr(), key_nr+1);
1132
case HA_ERR_FOUND_DUPP_UNIQUE:
1133
textno=ER_DUP_UNIQUE;
1135
case HA_ERR_RECORD_CHANGED:
1136
textno=ER_CHECKREAD;
1138
case HA_ERR_CRASHED:
1139
textno=ER_NOT_KEYFILE;
1141
case HA_ERR_WRONG_IN_RECORD:
1142
textno= ER_CRASHED_ON_USAGE;
1144
case HA_ERR_CRASHED_ON_USAGE:
1145
textno=ER_CRASHED_ON_USAGE;
1147
case HA_ERR_NOT_A_TABLE:
1150
case HA_ERR_CRASHED_ON_REPAIR:
1151
textno=ER_CRASHED_ON_REPAIR;
1153
case HA_ERR_OUT_OF_MEM:
1154
textno=ER_OUT_OF_RESOURCES;
1156
case HA_ERR_WRONG_COMMAND:
1157
textno=ER_ILLEGAL_HA;
1159
case HA_ERR_OLD_FILE:
1160
textno=ER_OLD_KEYFILE;
1162
case HA_ERR_UNSUPPORTED:
1163
textno=ER_UNSUPPORTED_EXTENSION;
1165
case HA_ERR_RECORD_FILE_FULL:
1166
case HA_ERR_INDEX_FILE_FULL:
1167
textno=ER_RECORD_FILE_FULL;
1169
case HA_ERR_LOCK_WAIT_TIMEOUT:
1170
textno=ER_LOCK_WAIT_TIMEOUT;
1172
case HA_ERR_LOCK_TABLE_FULL:
1173
textno=ER_LOCK_TABLE_FULL;
1175
case HA_ERR_LOCK_DEADLOCK:
1176
textno=ER_LOCK_DEADLOCK;
1178
case HA_ERR_READ_ONLY_TRANSACTION:
1179
textno=ER_READ_ONLY_TRANSACTION;
1181
case HA_ERR_CANNOT_ADD_FOREIGN:
1182
textno=ER_CANNOT_ADD_FOREIGN;
1184
case HA_ERR_ROW_IS_REFERENCED:
1187
get_error_message(error, &str);
1188
my_error(ER_ROW_IS_REFERENCED_2, MYF(0), str.c_ptr_safe());
1191
case HA_ERR_NO_REFERENCED_ROW:
1194
get_error_message(error, &str);
1195
my_error(ER_NO_REFERENCED_ROW_2, MYF(0), str.c_ptr_safe());
1198
case HA_ERR_TABLE_DEF_CHANGED:
1199
textno=ER_TABLE_DEF_CHANGED;
1201
case HA_ERR_NO_SUCH_TABLE:
1203
my_error(ER_NO_SUCH_TABLE, MYF(0), table->s->db.str,
1204
table->s->table_name.str);
1206
case HA_ERR_RBR_LOGGING_FAILED:
1207
textno= ER_BINLOG_ROW_LOGGING_FAILED;
1209
case HA_ERR_DROP_INDEX_FK:
1212
const char *ptr= "???";
1213
uint32_t key_nr= table->get_dup_key(error);
1214
if ((int) key_nr >= 0)
1215
ptr= table->key_info[key_nr].name;
1216
my_error(ER_DROP_INDEX_FK, MYF(0), ptr);
1219
case HA_ERR_TABLE_NEEDS_UPGRADE:
1220
textno=ER_TABLE_NEEDS_UPGRADE;
1222
case HA_ERR_TABLE_READONLY:
1223
textno= ER_OPEN_AS_READONLY;
1225
case HA_ERR_AUTOINC_READ_FAILED:
1226
textno= ER_AUTOINC_READ_FAILED;
1228
case HA_ERR_AUTOINC_ERANGE:
1229
textno= ER_WARN_DATA_OUT_OF_RANGE;
1231
case HA_ERR_LOCK_OR_ACTIVE_TRANSACTION:
1232
my_message(ER_LOCK_OR_ACTIVE_TRANSACTION,
1233
ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0));
1238
The error was "unknown" to this function.
1239
Ask Cursor if it has got a message for this error
1241
bool temporary= false;
1243
temporary= get_error_message(error, &str);
1244
if (!str.is_empty())
1246
const char* engine_name= getName().c_str();
1248
my_error(ER_GET_TEMPORARY_ERRMSG, MYF(0), error, str.ptr(),
1251
my_error(ER_GET_ERRMSG, MYF(0), error, str.ptr(), engine_name);
1255
my_error(ER_GET_ERRNO,errflag,error);
1260
my_error(textno, errflag, table->s->table_name.str, error);
1265
Return an error message specific to this Cursor.
1267
@param error error code previously returned by Cursor
1268
@param buf pointer to String where to add error message
1271
Returns true if this is a temporary error
1273
bool plugin::StorageEngine::get_error_message(int , String* )
1279
void plugin::StorageEngine::print_keydup_error(uint32_t key_nr, const char *msg, Table &table)
1281
/* Write the duplicated key in the error message */
1282
char key[MAX_KEY_LENGTH];
1283
String str(key,sizeof(key),system_charset_info);
1285
if (key_nr == MAX_KEY)
1287
/* Key is unknown */
1288
str.copy("", 0, system_charset_info);
1289
my_printf_error(ER_DUP_ENTRY, msg, MYF(0), str.c_ptr(), "*UNKNOWN*");
1293
/* Table is opened and defined at this point */
1294
key_unpack(&str, &table, (uint32_t) key_nr);
1295
uint32_t max_length=DRIZZLE_ERRMSG_SIZE-(uint32_t) strlen(msg);
1296
if (str.length() >= max_length)
1298
str.length(max_length-4);
1299
str.append(STRING_WITH_LEN("..."));
1301
my_printf_error(ER_DUP_ENTRY, msg,
1302
MYF(0), str.c_ptr(), table.key_info[key_nr].name);
1307
int plugin::StorageEngine::deleteDefinitionFromPath(TableIdentifier &identifier)
1309
string path(identifier.getPath());
1311
path.append(DEFAULT_DEFINITION_FILE_EXT);
1313
return my_delete(path.c_str(), MYF(0));
1316
int plugin::StorageEngine::renameDefinitionFromPath(TableIdentifier &dest, TableIdentifier &src)
1318
string src_path(src.getPath());
1319
string dest_path(dest.getPath());
1321
src_path.append(DEFAULT_DEFINITION_FILE_EXT);
1322
dest_path.append(DEFAULT_DEFINITION_FILE_EXT);
1324
return my_rename(src_path.c_str(), dest_path.c_str(), MYF(MY_WME));
1327
int plugin::StorageEngine::writeDefinitionFromPath(TableIdentifier &identifier, message::Table &table_proto)
1329
string file_name(identifier.getPath());
1331
file_name.append(DEFAULT_DEFINITION_FILE_EXT);
1333
int fd= open(file_name.c_str(), O_RDWR|O_CREAT|O_TRUNC, my_umask);
1338
google::protobuf::io::ZeroCopyOutputStream* output=
1339
new google::protobuf::io::FileOutputStream(fd);
1341
if (table_proto.SerializeToZeroCopyStream(output) == false)
1354
} /* namespace drizzled */