186
static bool dropdb_storage_engine(Session *,
187
st_plugin_int *plugin,
190
StorageEngine *engine= plugin_data(plugin, StorageEngine *);
191
if (engine->is_enabled())
192
engine->drop_database((char *)path);
197
void ha_drop_database(char* path)
199
plugin_foreach(NULL, dropdb_storage_engine, DRIZZLE_STORAGE_ENGINE_PLUGIN, path);
203
static bool closecon_storage_engine(Session *session, st_plugin_int *plugin,
206
StorageEngine *engine= plugin_data(plugin, StorageEngine *);
208
there's no need to rollback here as all transactions must
209
be rolled back already
211
if (engine->is_enabled() &&
212
session_get_ha_data(session, engine))
213
engine->close_connection(session);
220
don't bother to rollback here, it's done already
222
void ha_close_connection(Session* session)
224
plugin_foreach(session, closecon_storage_engine, DRIZZLE_STORAGE_ENGINE_PLUGIN, 0);
227
185
/* ========================================================================
228
186
======================= TRANSACTIONS ===================================*/
872
static bool xacommit_storage_engine(Session *,
873
st_plugin_int *plugin,
876
StorageEngine *engine= plugin_data(plugin, StorageEngine *);
877
if (engine->is_enabled())
879
engine->commit_by_xid(((struct xaengine_st *)arg)->xid);
880
((struct xaengine_st *)arg)->result= 0;
885
static bool xarollback_storage_engine(Session *,
886
st_plugin_int *plugin,
889
StorageEngine *engine= plugin_data(plugin, StorageEngine *);
890
if (engine->is_enabled())
892
engine->rollback_by_xid(((struct xaengine_st *)arg)->xid);
893
((struct xaengine_st *)arg)->result= 0;
899
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
901
struct xaengine_st xaop;
905
plugin_foreach(NULL, commit ? xacommit_storage_engine : xarollback_storage_engine,
906
DRIZZLE_STORAGE_ENGINE_PLUGIN, &xaop);
912
recover() step of xa.
915
there are three modes of operation:
916
- automatic recover after a crash
917
in this case commit_list != 0, tc_heuristic_recover==0
918
all xids from commit_list are committed, others are rolled back
919
- manual (heuristic) recover
920
in this case commit_list==0, tc_heuristic_recover != 0
921
DBA has explicitly specified that all prepared transactions should
922
be committed (or rolled back).
923
- no recovery (MySQL did not detect a crash)
924
in this case commit_list==0, tc_heuristic_recover == 0
925
there should be no prepared transactions in this case.
929
int len, found_foreign_xids, found_my_xids;
935
static bool xarecover_storage_engine(Session *,
936
st_plugin_int *plugin,
939
StorageEngine *engine= plugin_data(plugin, StorageEngine *);
940
struct xarecover_st *info= (struct xarecover_st *) arg;
943
if (engine->is_enabled())
945
while ((got= engine->recover(info->list, info->len)) > 0 )
947
errmsg_printf(ERRMSG_LVL_INFO,
948
_("Found %d prepared transaction(s) in %s"),
949
got, engine->getName().c_str());
950
for (int i=0; i < got; i ++)
952
my_xid x=info->list[i].get_my_xid();
953
if (!x) // not "mine" - that is generated by external TM
955
xid_cache_insert(info->list+i, XA_PREPARED);
956
info->found_foreign_xids++;
961
info->found_my_xids++;
965
if (info->commit_list ?
966
hash_search(info->commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
967
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
969
engine->commit_by_xid(info->list+i);
973
engine->rollback_by_xid(info->list+i);
983
int ha_recover(HASH *commit_list)
985
struct xarecover_st info;
986
info.found_foreign_xids= info.found_my_xids= 0;
987
info.commit_list= commit_list;
988
info.dry_run= (info.commit_list==0 && tc_heuristic_recover==0);
991
/* commit_list and tc_heuristic_recover cannot be set both */
992
assert(info.commit_list==0 || tc_heuristic_recover==0);
993
/* if either is set, total_ha_2pc must be set too */
994
assert(info.dry_run);
996
if (total_ha_2pc <= 1)
999
if (info.commit_list)
1000
errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
1003
#ifndef WILL_BE_DELETED_LATER
1006
for now, only InnoDB supports 2pc. It means we can always safely
1007
rollback all pending transactions, without risking inconsistent data
1010
assert(total_ha_2pc == 2); // only InnoDB and binlog
1011
tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
1016
for (info.len= MAX_XID_LIST_SIZE ;
1017
info.list==0 && info.len > MIN_XID_LIST_SIZE; info.len/=2)
1019
info.list=(XID *)malloc(info.len*sizeof(XID));
1023
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), info.len*sizeof(XID));
1027
plugin_foreach(NULL, xarecover_storage_engine,
1028
DRIZZLE_STORAGE_ENGINE_PLUGIN, &info);
1030
free((unsigned char*)info.list);
1031
if (info.found_foreign_xids)
1032
errmsg_printf(ERRMSG_LVL_WARN, _("Found %d prepared XA transactions"),
1033
info.found_foreign_xids);
1034
if (info.dry_run && info.found_my_xids)
1036
errmsg_printf(ERRMSG_LVL_ERROR,
1037
_("Found %d prepared transactions! It means that drizzled "
1038
"was not shut down properly last time and critical "
1039
"recovery information (last binlog or %s file) was "
1040
"manually deleted after a crash. You have to start "
1041
"drizzled with the --tc-heuristic-recover switch to "
1042
"commit or rollback pending transactions."),
1043
info.found_my_xids, opt_tc_log_file);
1046
if (info.commit_list)
1047
errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
1052
828
return the list of XID's to a client, the same way SHOW commands do.
1101
This function should be called when MySQL sends rows of a SELECT result set
1102
or the EOF mark to the client. It releases a possible adaptive hash index
1103
S-latch held by session in InnoDB and also releases a possible InnoDB query
1104
FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
1105
keep them over several calls of the InnoDB handler interface when a join
1106
is executed. But when we let the control to pass to the client they have
1107
to be released because if the application program uses mysql_use_result(),
1108
it may deadlock on the S-latch if the application on another connection
1109
performs another SQL query. In MySQL-4.1 this is even more important because
1110
there a connection can have several SELECT queries open at the same time.
1112
@param session the thread handle of the current connection
1117
static bool release_temporary_latches(Session *session, st_plugin_int *plugin,
1120
StorageEngine *engine= plugin_data(plugin, StorageEngine *);
1122
if (engine->is_enabled())
1123
engine->release_temporary_latches(session);
1129
int ha_release_temporary_latches(Session *session)
1131
plugin_foreach(session, release_temporary_latches, DRIZZLE_STORAGE_ENGINE_PLUGIN,
1137
876
int ha_rollback_to_savepoint(Session *session, SAVEPOINT *sv)
1243
static bool snapshot_storage_engine(Session *session, st_plugin_int *plugin, void *arg)
1245
StorageEngine *engine= plugin_data(plugin, StorageEngine *);
1246
if (engine->is_enabled())
1248
engine->start_consistent_snapshot(session);
1249
*((bool *)arg)= false;
1254
int ha_start_consistent_snapshot(Session *session)
1258
plugin_foreach(session, snapshot_storage_engine, DRIZZLE_STORAGE_ENGINE_PLUGIN, &warn);
1261
Same idea as when one wants to CREATE TABLE in one engine which does not
1265
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_WARN, ER_UNKNOWN_ERROR,
1266
"This Drizzle server does not support any "
1267
"consistent-read capable storage engine");
1272
static bool flush_storage_engine(Session *,
1273
st_plugin_int *plugin,
1276
StorageEngine *engine= plugin_data(plugin, StorageEngine *);
1277
if (engine->is_enabled() &&
1278
engine->flush_logs())
1284
bool ha_flush_logs(StorageEngine *engine)
1288
if (plugin_foreach(NULL, flush_storage_engine,
1289
DRIZZLE_STORAGE_ENGINE_PLUGIN, 0))
1294
if ((!engine->is_enabled()) ||
1295
(engine->flush_logs()))
1301
static const char *check_lowercase_names(handler *file, const char *path,
1304
if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED))
1307
/* Ensure that table handler get path in lower case */
1308
if (tmp_path != path)
1309
strcpy(tmp_path, path);
1312
we only should turn into lowercase database/table part
1313
so start the process after homedirectory
1315
my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
1321
An interceptor to hijack the text of the error message without
1322
setting an error in the thread. We need the text to present it
1323
in the form of a warning to the user.
1326
struct Ha_delete_table_error_handler: public Internal_error_handler
1329
Ha_delete_table_error_handler() : Internal_error_handler() {}
1330
virtual bool handle_error(uint32_t sql_errno,
1331
const char *message,
1332
DRIZZLE_ERROR::enum_warning_level level,
1334
char buff[DRIZZLE_ERRMSG_SIZE];
1339
Ha_delete_table_error_handler::
1340
handle_error(uint32_t ,
1341
const char *message,
1342
DRIZZLE_ERROR::enum_warning_level ,
1345
/* Grab the error message */
1346
strncpy(buff, message, sizeof(buff)-1);
1351
struct storage_engine_delete_table_args {
1358
static bool deletetable_storage_engine(Session *,
1359
st_plugin_int *plugin,
1362
struct storage_engine_delete_table_args *dtargs= (struct storage_engine_delete_table_args *) args;
1364
Session *session= dtargs->session;
1365
const char *path= dtargs->path;
1368
char tmp_path[FN_REFLEN];
1370
if(dtargs->error!=ENOENT) /* already deleted table */
1373
StorageEngine *engine= plugin_data(plugin, StorageEngine *);
1378
if (!engine->is_enabled())
1381
if ((file= engine->create(NULL, session->mem_root)))
1386
path= check_lowercase_names(file, path, tmp_path);
1387
int error= file->ha_delete_table(path);
1391
dtargs->error= error;
1393
delete dtargs->file;
1404
This should return ENOENT if the file doesn't exists.
1405
The .frm file will be deleted only if we return 0 or ENOENT
1407
int ha_delete_table(Session *session, const char *path,
1408
const char *db, const char *alias, bool generate_warning)
1410
TABLE_SHARE dummy_share;
1413
struct storage_engine_delete_table_args dtargs;
1414
dtargs.error= ENOENT;
1415
dtargs.session= session;
1419
plugin_foreach(NULL, deletetable_storage_engine, DRIZZLE_STORAGE_ENGINE_PLUGIN,
1422
memset(&dummy_table, 0, sizeof(dummy_table));
1423
memset(&dummy_share, 0, sizeof(dummy_share));
1424
dummy_table.s= &dummy_share;
1426
if (dtargs.error && generate_warning)
1429
Because file->print_error() use my_error() to generate the error message
1430
we use an internal error handler to intercept it and store the text
1431
in a temporary buffer. Later the message will be presented to user
1434
Ha_delete_table_error_handler ha_delete_table_error_handler;
1436
/* Fill up strucutures that print_error may need */
1437
dummy_share.path.str= (char*) path;
1438
dummy_share.path.length= strlen(path);
1439
dummy_share.db.str= (char*) db;
1440
dummy_share.db.length= strlen(db);
1441
dummy_share.table_name.str= (char*) alias;
1442
dummy_share.table_name.length= strlen(alias);
1443
dummy_table.alias= alias;
1447
handler *file= dtargs.file;
1448
file->change_table_ptr(&dummy_table, &dummy_share);
1450
session->push_internal_handler(&ha_delete_table_error_handler);
1451
file->print_error(dtargs.error, 0);
1453
session->pop_internal_handler();
1456
dtargs.error= -1; /* General form of fail. maybe bad FRM */
1459
XXX: should we convert *all* errors to warnings here?
1460
What if the error is fatal?
1462
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, dtargs.error,
1463
ha_delete_table_error_handler.buff);
1469
return dtargs.error;
1472
985
/****************************************************************************
1473
986
** General handler functions
2825
2338
** Some general functions that isn't in the handler class
2826
2339
****************************************************************************/
2829
Initiates table-file and calls appropriate database-creator.
2836
int ha_create_table(Session *session, const char *path,
2837
const char *db, const char *table_name,
2838
HA_CREATE_INFO *create_info,
2839
bool update_create_info)
2843
char name_buff[FN_REFLEN];
2847
init_tmp_table_share(session, &share, db, 0, table_name, path);
2848
if (open_table_def(session, &share, 0) ||
2849
open_table_from_share(session, &share, "", 0, (uint32_t) READ_ALL, 0, &table,
2853
if (update_create_info)
2854
table.updateCreateInfo(create_info);
2856
name= check_lowercase_names(table.file, share.path.str, name_buff);
2858
error= table.file->ha_create(name, &table, create_info);
2859
table.closefrm(false);
2862
sprintf(name_buff,"%s.%s",db,table_name);
2863
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
2866
free_table_share(&share);
2870
2342
void st_ha_check_opt::init()
2967
Call this function in order to give the handler the possiblity
2968
to ask engine if there are any new tables that should be written to disk
2969
or any dropped tables that need to be removed from disk
2971
struct st_find_files_args
2977
List<LEX_STRING> *files;
2981
Ask handler if the table exists in engine.
2983
HA_ERR_NO_SUCH_TABLE Table does not exist
2985
HA_ERR_TABLE_EXIST Table exists
2989
struct st_table_exists_in_storage_engine_args
2994
StorageEngine* engine;
2997
static bool table_exists_in_storage_engine(Session *session,
2998
st_plugin_int *plugin,
3001
st_table_exists_in_storage_engine_args *vargs= (st_table_exists_in_storage_engine_args *)arg;
3002
StorageEngine *engine= plugin_data(plugin, StorageEngine *);
3004
int err= HA_ERR_NO_SUCH_TABLE;
3006
if (engine->is_enabled())
3007
err = engine->table_exists_in_engine(session, vargs->db, vargs->name);
3010
if (vargs->err == HA_ERR_TABLE_EXIST)
3012
vargs->engine= engine;
3019
int ha_table_exists_in_engine(Session* session,
3020
const char* db, const char* name,
3021
StorageEngine **engine)
3023
st_table_exists_in_storage_engine_args args= {db, name, HA_ERR_NO_SUCH_TABLE, NULL};
3024
plugin_foreach(session, table_exists_in_storage_engine,
3025
DRIZZLE_STORAGE_ENGINE_PLUGIN, &args);
3027
if(args.err==HA_ERR_NO_SUCH_TABLE)
3029
/* Default way of knowing if a table exists. (checking .frm exists) */
3031
char path[FN_REFLEN];
3032
build_table_filename(path, sizeof(path),
3034
if (table_proto_exists(path)==EEXIST)
3035
args.err= HA_ERR_TABLE_EXIST;
3037
args.err= HA_ERR_NO_SUCH_TABLE;
3039
if(args.err==HA_ERR_TABLE_EXIST)
3041
drizzle::Table table;
3042
build_table_filename(path, sizeof(path),
3043
db, name, ".dfe", 0);
3044
if(drizzle_read_table_proto(path, &table)==0)
3046
LEX_STRING engine_name= { (char*)table.engine().name().c_str(),
3047
strlen(table.engine().name().c_str()) };
3048
st_plugin_int *plugin= ha_resolve_by_name(session, &engine_name);
3050
args.engine= static_cast<StorageEngine *>(plugin->data);
3056
*engine= args.engine;
3062
2440
Calculate cost of 'index only' scan for given index and number of records
4075
Returns a list of all known extensions.
4077
No mutexes, worst case race is a minor surplus memory allocation
4078
We have to recreate the extension map if mysqld is restarted (for example
4082
pointer pointer to TYPELIB structure
4084
static bool exts_handlerton(Session *,
4085
st_plugin_int *plugin,
4088
List<char> *found_exts= (List<char> *) arg;
4089
StorageEngine *engine= plugin_data(plugin, StorageEngine *);
4091
if (engine->is_enabled() &&
4092
(file= engine->create((TABLE_SHARE*) 0, current_session->mem_root)))
4094
List_iterator_fast<char> it(*found_exts);
4095
const char **ext, *old_ext;
4097
for (ext= file->bas_ext(); *ext; ext++)
4099
while ((old_ext= it++))
4101
if (!strcmp(old_ext, *ext))
4105
found_exts->push_back((char *) *ext);
4114
TYPELIB *ha_known_exts(void)
4116
if (!known_extensions.type_names || mysys_usage_id != known_extensions_id)
4118
List<char> found_exts;
4119
const char **ext, *old_ext;
4121
known_extensions_id= mysys_usage_id;
4123
plugin_foreach(NULL, exts_handlerton,
4124
DRIZZLE_STORAGE_ENGINE_PLUGIN, &found_exts);
4126
ext= (const char **) malloc(sizeof(char *)*
4127
(found_exts.elements+1));
4131
known_extensions.count= found_exts.elements;
4132
known_extensions.type_names= ext;
4134
List_iterator_fast<char> it(found_exts);
4135
while ((old_ext= it++))
4139
return &known_extensions;
4143
3452
static bool stat_print(Session *session, const char *type, uint32_t type_len,
4144
3453
const char *file, uint32_t file_len,
4145
3454
const char *status, uint32_t status_len)