181
144
return(get_new_handler(share, alloc, ha_default_storage_engine(current_session)));
147
class StorageEngineCloseConnection
148
: public unary_function<StorageEngine *, void>
152
StorageEngineCloseConnection(Session *session_arg) : session(session_arg) {}
154
there's no need to rollback here as all transactions must
155
be rolled back already
157
inline result_type operator() (argument_type engine)
159
if (engine->is_enabled() &&
160
session_get_ha_data(session, engine))
161
engine->close_connection(session);
167
don't bother to rollback here, it's done already
169
void ha_close_connection(Session* session)
171
for_each(all_engines.begin(), all_engines.end(),
172
StorageEngineCloseConnection(session));
175
void ha_drop_database(char* path)
177
for_each(all_engines.begin(), all_engines.end(),
178
bind2nd(mem_fun(&StorageEngine::drop_database),path));
181
int ha_commit_or_rollback_by_xid(XID *xid, bool commit)
186
transform(all_engines.begin(), all_engines.end(), results.begin(),
187
bind2nd(mem_fun(&StorageEngine::commit_by_xid),xid));
189
transform(all_engines.begin(), all_engines.end(), results.begin(),
190
bind2nd(mem_fun(&StorageEngine::rollback_by_xid),xid));
192
if (find_if(results.begin(), results.end(), bind2nd(equal_to<int>(),0))
201
This function should be called when MySQL sends rows of a SELECT result set
202
or the EOF mark to the client. It releases a possible adaptive hash index
203
S-latch held by session in InnoDB and also releases a possible InnoDB query
204
FIFO ticket to enter InnoDB. To save CPU time, InnoDB allows a session to
205
keep them over several calls of the InnoDB handler interface when a join
206
is executed. But when we let the control to pass to the client they have
207
to be released because if the application program uses mysql_use_result(),
208
it may deadlock on the S-latch if the application on another connection
209
performs another SQL query. In MySQL-4.1 this is even more important because
210
there a connection can have several SELECT queries open at the same time.
212
@param session the thread handle of the current connection
217
int ha_release_temporary_latches(Session *session)
219
for_each(all_engines.begin(), all_engines.end(),
220
bind2nd(mem_fun(&StorageEngine::release_temporary_latches),session));
225
bool ha_flush_logs(StorageEngine *engine)
229
if (find_if(all_engines.begin(), all_engines.end(),
230
mem_fun(&StorageEngine::flush_logs))
231
!= all_engines.begin())
236
if ((!engine->is_enabled()) ||
237
(engine->flush_logs()))
244
recover() step of xa.
247
there are three modes of operation:
248
- automatic recover after a crash
249
in this case commit_list != 0, tc_heuristic_recover==0
250
all xids from commit_list are committed, others are rolled back
251
- manual (heuristic) recover
252
in this case commit_list==0, tc_heuristic_recover != 0
253
DBA has explicitly specified that all prepared transactions should
254
be committed (or rolled back).
255
- no recovery (MySQL did not detect a crash)
256
in this case commit_list==0, tc_heuristic_recover == 0
257
there should be no prepared transactions in this case.
259
class XARecover : unary_function<StorageEngine *, void>
261
int trans_len, found_foreign_xids, found_my_xids;
267
XARecover(XID *trans_list_arg, int trans_len_arg,
268
HASH *commit_list_arg, bool dry_run_arg)
269
: trans_len(trans_len_arg), found_foreign_xids(0), found_my_xids(0),
270
trans_list(trans_list_arg), commit_list(commit_list_arg),
276
return found_foreign_xids;
281
return found_my_xids;
284
result_type operator() (argument_type engine)
289
if (engine->is_enabled())
291
while ((got= engine->recover(trans_list, trans_len)) > 0 )
293
errmsg_printf(ERRMSG_LVL_INFO,
294
_("Found %d prepared transaction(s) in %s"),
295
got, engine->getName().c_str());
296
for (int i=0; i < got; i ++)
298
my_xid x=trans_list[i].get_my_xid();
299
if (!x) // not "mine" - that is generated by external TM
301
xid_cache_insert(trans_list+i, XA_PREPARED);
302
found_foreign_xids++;
312
hash_search(commit_list, (unsigned char *)&x, sizeof(x)) != 0 :
313
tc_heuristic_recover == TC_HEURISTIC_RECOVER_COMMIT)
315
engine->commit_by_xid(trans_list+i);
319
engine->rollback_by_xid(trans_list+i);
330
int ha_recover(HASH *commit_list)
332
XID *trans_list= NULL;
335
bool dry_run= (commit_list==0 && tc_heuristic_recover==0);
337
/* commit_list and tc_heuristic_recover cannot be set both */
338
assert(commit_list==0 || tc_heuristic_recover==0);
340
/* if either is set, total_ha_2pc must be set too */
341
if (total_ha_2pc <= 1)
345
#ifndef WILL_BE_DELETED_LATER
348
for now, only InnoDB supports 2pc. It means we can always safely
349
rollback all pending transactions, without risking inconsistent data
352
assert(total_ha_2pc == 2); // only InnoDB and binlog
353
tc_heuristic_recover= TC_HEURISTIC_RECOVER_ROLLBACK; // forcing ROLLBACK
356
for (trans_len= MAX_XID_LIST_SIZE ;
357
trans_list==0 && trans_len > MIN_XID_LIST_SIZE; trans_len/=2)
359
trans_list=(XID *)malloc(trans_len*sizeof(XID));
363
errmsg_printf(ERRMSG_LVL_ERROR, ER(ER_OUTOFMEMORY), trans_len*sizeof(XID));
368
errmsg_printf(ERRMSG_LVL_INFO, _("Starting crash recovery..."));
371
XARecover recover_func(trans_list, trans_len, commit_list, dry_run);
372
for_each(all_engines.begin(), all_engines.end(), recover_func);
375
if (recover_func.getForeignXIDs())
376
errmsg_printf(ERRMSG_LVL_WARN,
377
_("Found %d prepared XA transactions"),
378
recover_func.getForeignXIDs());
379
if (dry_run && recover_func.getMyXIDs())
381
errmsg_printf(ERRMSG_LVL_ERROR,
382
_("Found %d prepared transactions! It means that drizzled "
383
"was not shut down properly last time and critical "
384
"recovery information (last binlog or %s file) was "
385
"manually deleted after a crash. You have to start "
386
"drizzled with the --tc-heuristic-recover switch to "
387
"commit or rollback pending transactions."),
388
recover_func.getMyXIDs(), opt_tc_log_file);
392
errmsg_printf(ERRMSG_LVL_INFO, _("Crash recovery finished."));
396
int ha_start_consistent_snapshot(Session *session)
398
for_each(all_engines.begin(), all_engines.end(),
399
bind2nd(mem_fun(&StorageEngine::start_consistent_snapshot),session));
404
Ask handler if the table exists in engine.
406
HA_ERR_NO_SUCH_TABLE Table does not exist
408
HA_ERR_TABLE_EXIST Table exists
413
class TableExistsInStorageEngine: public unary_function<StorageEngine *,bool>
419
TableExistsInStorageEngine(Session *session_arg,
420
const char *db_arg, const char *name_arg)
421
:session(session_arg), db(db_arg), name(name_arg) {}
422
result_type operator() (argument_type engine)
424
int ret= engine->table_exists_in_engine(session, db, name);
425
return ret == HA_ERR_TABLE_EXIST;
430
Call this function in order to give the handler the possiblity
431
to ask engine if there are any new tables that should be written to disk
432
or any dropped tables that need to be removed from disk
434
int ha_table_exists_in_engine(Session* session,
435
const char* db, const char* name,
436
StorageEngine **engine_arg)
438
StorageEngine *engine= NULL;
440
drizzled::Registry<StorageEngine *>::iterator iter=
441
find_if(all_engines.begin(), all_engines.end(),
442
TableExistsInStorageEngine(session, db, name));
443
if (iter != all_engines.end())
449
/* Default way of knowing if a table exists. (checking .frm exists) */
451
char path[FN_REFLEN];
452
build_table_filename(path, sizeof(path),
454
if (table_proto_exists(path)==EEXIST)
456
drizzle::Table table;
457
build_table_filename(path, sizeof(path),
458
db, name, ".dfe", 0);
459
if(drizzle_read_table_proto(path, &table)==0)
461
LEX_STRING engine_name= { (char*)table.engine().name().c_str(),
462
strlen(table.engine().name().c_str()) };
463
engine= ha_resolve_by_name(session, &engine_name);
472
return HA_ERR_NO_SUCH_TABLE;
473
return HA_ERR_TABLE_EXIST;
477
static const char *check_lowercase_names(handler *file, const char *path,
480
if (lower_case_table_names != 2 || (file->ha_table_flags() & HA_FILE_BASED))
483
/* Ensure that table handler get path in lower case */
484
if (tmp_path != path)
485
strcpy(tmp_path, path);
488
we only should turn into lowercase database/table part
489
so start the process after homedirectory
491
my_casedn_str(files_charset_info, tmp_path + drizzle_data_home_len);
496
An interceptor to hijack the text of the error message without
497
setting an error in the thread. We need the text to present it
498
in the form of a warning to the user.
501
class Ha_delete_table_error_handler: public Internal_error_handler
504
Ha_delete_table_error_handler() : Internal_error_handler() {}
505
virtual bool handle_error(uint32_t sql_errno,
507
DRIZZLE_ERROR::enum_warning_level level,
509
char buff[DRIZZLE_ERRMSG_SIZE];
514
Ha_delete_table_error_handler::
515
handle_error(uint32_t ,
517
DRIZZLE_ERROR::enum_warning_level ,
520
/* Grab the error message */
521
strncpy(buff, message, sizeof(buff)-1);
526
class DeleteTableStorageEngine
527
: public unary_function<StorageEngine *, void>
534
DeleteTableStorageEngine(Session *session_arg, const char *path_arg,
535
handler **file_arg, int *error_arg)
536
: session(session_arg), path(path_arg), file(file_arg), dt_error(error_arg) {}
538
result_type operator() (argument_type engine)
542
char tmp_path[FN_REFLEN];
544
if(*dt_error!=ENOENT) /* already deleted table */
550
if (!engine->is_enabled())
553
if ((tmp_file= engine->create(NULL, session->mem_root)))
558
path= check_lowercase_names(tmp_file, path, tmp_path);
559
int tmp_error= tmp_file->ha_delete_table(path);
561
if(tmp_error!=ENOENT)
563
*dt_error= tmp_error;
577
This should return ENOENT if the file doesn't exists.
578
The .frm file will be deleted only if we return 0 or ENOENT
580
int ha_delete_table(Session *session, const char *path,
581
const char *db, const char *alias, bool generate_warning)
583
TABLE_SHARE dummy_share;
585
memset(&dummy_table, 0, sizeof(dummy_table));
586
memset(&dummy_share, 0, sizeof(dummy_share));
588
dummy_table.s= &dummy_share;
593
for_each(all_engines.begin(), all_engines.end(),
594
DeleteTableStorageEngine(session, path, &file, &error));
596
if (error && generate_warning)
599
Because file->print_error() use my_error() to generate the error message
600
we use an internal error handler to intercept it and store the text
601
in a temporary buffer. Later the message will be presented to user
604
Ha_delete_table_error_handler ha_delete_table_error_handler;
606
/* Fill up strucutures that print_error may need */
607
dummy_share.path.str= (char*) path;
608
dummy_share.path.length= strlen(path);
609
dummy_share.db.str= (char*) db;
610
dummy_share.db.length= strlen(db);
611
dummy_share.table_name.str= (char*) alias;
612
dummy_share.table_name.length= strlen(alias);
613
dummy_table.alias= alias;
618
file->change_table_ptr(&dummy_table, &dummy_share);
620
session->push_internal_handler(&ha_delete_table_error_handler);
621
file->print_error(error, 0);
623
session->pop_internal_handler();
626
error= -1; /* General form of fail. maybe bad FRM */
629
XXX: should we convert *all* errors to warnings here?
630
What if the error is fatal?
632
push_warning(session, DRIZZLE_ERROR::WARN_LEVEL_ERROR, error,
633
ha_delete_table_error_handler.buff);
643
Initiates table-file and calls appropriate database-creator.
650
int ha_create_table(Session *session, const char *path,
651
const char *db, const char *table_name,
652
HA_CREATE_INFO *create_info,
653
bool update_create_info)
657
char name_buff[FN_REFLEN];
661
init_tmp_table_share(session, &share, db, 0, table_name, path);
662
if (open_table_def(session, &share, 0) ||
663
open_table_from_share(session, &share, "", 0, (uint32_t) READ_ALL, 0, &table,
667
if (update_create_info)
668
table.updateCreateInfo(create_info);
670
name= check_lowercase_names(table.file, share.path.str, name_buff);
672
error= table.file->ha_create(name, &table, create_info);
673
table.closefrm(false);
676
sprintf(name_buff,"%s.%s",db,table_name);
677
my_error(ER_CANT_CREATE_TABLE, MYF(ME_BELL+ME_WAITTANG), name_buff, error);
680
free_table_share(&share);
185
685
int storage_engine_finalizer(st_plugin_int *plugin)
187
687
StorageEngine *engine= static_cast<StorageEngine *>(plugin->data);
189
all_engines.erase(engine->getName());
689
remove_storage_engine(engine);
191
691
if (engine && plugin->plugin->deinit)
192
692
(void)plugin->plugin->deinit(engine);