20 #include <drizzled/table.h>
21 #include <drizzled/error.h>
22 #include <drizzled/plugin/transactional_storage_engine.h>
23 #include <drizzled/session.h>
28 #include <drizzled/message/table.pb.h>
29 #include <drizzled/internal/m_string.h>
31 #include <drizzled/charset.h>
33 #include <boost/unordered_map.hpp>
35 #include "engine_state_history.h"
38 using namespace drizzled;
42 typedef multimap<string, string> state_multimap;
43 typedef multimap<string, string>::value_type state_pair;
44 typedef multimap<string, string>::iterator state_multimap_iter;
45 state_multimap engine_state_transitions;
46 state_multimap cursor_state_transitions;
48 void load_engine_state_transitions(state_multimap &states);
49 void load_cursor_state_transitions(state_multimap &states);
51 uint64_t next_cursor_id;
53 plugin::TransactionalStorageEngine *realEngine;
71 static uint32_t error_injected= 0;
73 #include <drizzled/function/math/int.h>
74 #include <drizzled/plugin/function.h>
82 const char *func_name()
const
84 return "seapitester_error_inject";
87 void fix_length_and_dec()
92 bool check_argument_count(
int n)
101 assert(fixed ==
true);
102 uint32_t err_to_inject= args[0]->val_int();
104 error_injected= err_to_inject;
106 return error_injected;
109 static plugin::TransactionalStorageEngine *getRealEngine()
111 return down_cast<plugin::TransactionalStorageEngine*>(plugin::StorageEngine::findByName(
"INNODB"));
114 static inline void ENGINE_NEW_STATE(
const string &new_state)
116 state_multimap_iter cur= engine_state_transitions.find(engine_state);
117 if (engine_state_transitions.count(engine_state) == 0)
119 std::cerr <<
"ERROR: Invalid engine state: " << engine_state << std::endl
120 <<
"This should *NEVER* happen."
122 <<
"i.e. you've really screwed it up and you should be ashamed of "
123 <<
"yourself." << std::endl;
124 assert(engine_state_transitions.count(engine_state));
127 for(cur= engine_state_transitions.lower_bound(engine_state);
128 cur != engine_state_transitions.upper_bound(engine_state);
131 if (new_state.compare((*cur).second) == 0)
135 if (cur == engine_state_transitions.end()
136 || new_state.compare((*cur).second))
138 std::cerr <<
"ERROR: Invalid Storage Engine state transition!" << std::endl
139 <<
"Cannot go from " << engine_state <<
" to " << new_state << std::endl;
143 engine_state= new_state;
144 engine_state_history.push_back(new_state);
146 std::cerr <<
"\tENGINE STATE : " << engine_state << std::endl;
149 static const string engine_name(
"STORAGE_ENGINE_API_TESTER");
159 :
Cursor(engine_arg, table_arg)
161 cursor_state=
"Cursor()";
163 id= ++next_cursor_id;
164 CURSOR_NEW_STATE(
"Cursor()");
168 { CURSOR_NEW_STATE(
"~Cursor()");
delete realCursor;}
171 int rnd_next(
unsigned char *buf) {
173 CURSOR_NEW_STATE(
"::rnd_next()");
175 if (error_injected == 3 && (count++ % 2))
177 user_session->markTransactionForRollback(
false);
178 return HA_ERR_LOCK_WAIT_TIMEOUT;
180 return realCursor->rnd_next(buf);
183 int rnd_pos(
unsigned char* buf,
unsigned char* pos) { CURSOR_NEW_STATE(
"::rnd_pos()");
return realCursor->rnd_pos(buf, pos); }
184 void position(
const unsigned char *record);
185 int info(uint32_t flag);
189 void get_auto_increment(uint64_t, uint64_t, uint64_t, uint64_t*, uint64_t*) {}
190 int doStartTableScan(
bool scan) { CURSOR_NEW_STATE(
"::doStartTableScan()");
return realCursor->doStartTableScan(scan); }
191 int doEndTableScan() { CURSOR_NEW_STATE(
"::doEndTableScan()");
return realCursor->doEndTableScan(); }
193 const char *index_type(uint32_t key_number);
195 int doStartIndexScan(uint32_t,
bool);
196 int index_read(
unsigned char *buf,
const unsigned char *key_ptr,
197 uint32_t key_len, drizzled::ha_rkey_function find_flag);
200 const unsigned char * key,
201 drizzled::key_part_map keypart_map,
202 drizzled::ha_rkey_function find_flag);
204 int index_next(
unsigned char * buf);
205 int doEndIndexScan();
206 int index_prev(
unsigned char * buf);
207 int index_first(
unsigned char * buf);
208 int index_last(
unsigned char * buf);
210 bool primary_key_is_clustered()
212 return realCursor->primary_key_is_clustered();
216 int doOpen(
const identifier::Table &identifier,
int mode, uint32_t test_if_locked);
224 int doInsertRecord(
unsigned char *buf)
227 CURSOR_NEW_STATE(
"::doInsertRecord()");
229 if (error_injected == 1 && (i++ % 2))
231 user_session->markTransactionForRollback(
false);
232 return HA_ERR_LOCK_WAIT_TIMEOUT;
235 if (error_injected == 2 && (i++ % 2))
237 user_session->markTransactionForRollback(
true);
238 return HA_ERR_LOCK_DEADLOCK;
241 return realCursor->doInsertRecord(buf);
244 int doUpdateRecord(
const unsigned char *old_row,
unsigned char *new_row)
246 CURSOR_NEW_STATE(
"::doUpdateRecord()");
247 return realCursor->doUpdateRecord(old_row, new_row);
252 CURSOR_NEW_STATE(
"::scan_time()");
253 CURSOR_NEW_STATE(
"locked");
254 return realCursor->scan_time();
257 int extra(
enum ha_extra_function operation)
259 return realCursor->extra(operation);
264 void CURSOR_NEW_STATE(
const string &new_state);
269 int SEAPITesterCursor::doOpen(
const identifier::Table &identifier,
int mode, uint32_t test_if_locked)
271 CURSOR_NEW_STATE(
"::doOpen()");
273 int r= realCursor->doOpen(identifier, mode, test_if_locked);
282 CURSOR_NEW_STATE(
"::reset()");
283 CURSOR_NEW_STATE(
"::doOpen()");
285 return realCursor->reset();
288 int SEAPITesterCursor::close()
290 CURSOR_NEW_STATE(
"::close()");
291 CURSOR_NEW_STATE(
"Cursor()");
293 return realCursor->close();
296 void SEAPITesterCursor::position(
const unsigned char *record)
298 CURSOR_NEW_STATE(
"::position()");
301 realCursor->ref= ref;
303 realCursor->position(record);
306 int SEAPITesterCursor::info(uint32_t flag)
309 CURSOR_NEW_STATE(
"::info()");
310 CURSOR_NEW_STATE(
"locked");
312 r= realCursor->info(flag);
314 if (flag & (HA_STATUS_VARIABLE|HA_STATUS_AUTO|HA_STATUS_CONST))
316 stats= realCursor->stats;
319 if (flag & HA_STATUS_ERRKEY)
320 errkey= realCursor->errkey;
325 const char * SEAPITesterCursor::index_type(uint32_t key_number)
327 CURSOR_NEW_STATE(
"::index_type()");
328 return realCursor->index_type(key_number);
331 int SEAPITesterCursor::doStartIndexScan(uint32_t keynr,
bool scan)
334 CURSOR_NEW_STATE(
"::doStartIndexScan()");
336 if (error_injected == 4)
338 CURSOR_NEW_STATE(
"::doStartIndexScan() ERROR");
339 CURSOR_NEW_STATE(
"locked");
340 return HA_ERR_LOCK_DEADLOCK;
343 r= realCursor->doStartIndexScan(keynr, scan);
345 active_index= realCursor->get_index();
350 int SEAPITesterCursor::index_read(
unsigned char *buf,
351 const unsigned char *key_ptr,
353 drizzled::ha_rkey_function find_flag)
355 CURSOR_NEW_STATE(
"::index_read()");
356 CURSOR_NEW_STATE(
"::doStartIndexScan()");
357 return realCursor->index_read(buf, key_ptr, key_len, find_flag);
362 const unsigned char * key,
363 drizzled::key_part_map keypart_map,
364 drizzled::ha_rkey_function find_flag)
366 CURSOR_NEW_STATE(
"::index_read_idx_map()");
367 CURSOR_NEW_STATE(
"locked");
368 return realCursor->index_read_idx_map(buf, index, key, keypart_map, find_flag);
371 int SEAPITesterCursor::index_next(
unsigned char * buf)
373 CURSOR_NEW_STATE(
"::index_next()");
374 CURSOR_NEW_STATE(
"::doStartIndexScan()");
375 return realCursor->index_next(buf);
378 int SEAPITesterCursor::doEndIndexScan()
380 CURSOR_NEW_STATE(
"::doEndIndexScan()");
381 CURSOR_NEW_STATE(
"locked");
382 int r= realCursor->doEndIndexScan();
384 active_index= realCursor->get_index();
389 int SEAPITesterCursor::index_prev(
unsigned char * buf)
391 CURSOR_NEW_STATE(
"::index_prev()");
392 CURSOR_NEW_STATE(
"::doStartIndexScan()");
393 return realCursor->index_prev(buf);
396 int SEAPITesterCursor::index_first(
unsigned char * buf)
398 CURSOR_NEW_STATE(
"::index_first()");
399 CURSOR_NEW_STATE(
"::doStartIndexScan()");
400 return realCursor->index_first(buf);
403 int SEAPITesterCursor::index_last(
unsigned char * buf)
405 CURSOR_NEW_STATE(
"::index_last()");
406 CURSOR_NEW_STATE(
"::doStartIndexScan()");
407 return realCursor->index_last(buf);
412 CURSOR_NEW_STATE(
"::external_lock()");
413 CURSOR_NEW_STATE(
"locked");
415 user_session= session;
417 return realCursor->external_lock(session, lock_type);
422 enum thr_lock_type lock_type)
425 CURSOR_NEW_STATE(
"::store_lock()");
427 return realCursor->store_lock(session, to, lock_type);
430 void SEAPITesterCursor::CURSOR_NEW_STATE(
const string &new_state)
432 state_multimap_iter cur= cursor_state_transitions.find(cursor_state);
433 if (cursor_state_transitions.count(cursor_state) == 0)
435 std::cerr <<
"ERROR: Invalid Cursor state: " << cursor_state << std::endl
436 <<
"This should *NEVER* happen."
438 <<
"i.e. you've really screwed it up and you should be ashamed of "
439 <<
"yourself." << std::endl;
440 assert(cursor_state_transitions.count(cursor_state));
443 for(cur= cursor_state_transitions.lower_bound(cursor_state);
444 cur != cursor_state_transitions.upper_bound(cursor_state);
447 if (new_state.compare((*cur).second) == 0)
451 if (cur == cursor_state_transitions.end()
452 || new_state.compare((*cur).second))
454 std::cerr <<
"ERROR: Invalid Cursor state transition!" << std::endl
455 <<
"Cursor " <<
this <<
"Cannot go from "
456 << cursor_state <<
" to " << new_state << std::endl;
460 cursor_state= new_state;
462 std::string cursor_state_str(
"Cursor ");
464 snprintf(nr,
sizeof(nr),
"%"PRIu64, this->
id);
465 cursor_state_str.append(nr);
466 cursor_state_str.append(
" ");
467 cursor_state_str.append(cursor_state);
469 engine_state_history.push_back(cursor_state_str);
471 std::cerr <<
"\t\tCursor " <<
this <<
" STATE : " << cursor_state << std::endl;
476 static const char *api_tester_exts[] = {
491 HTON_CAN_INDEX_BLOBS |
492 HTON_PRIMARY_KEY_IN_READ_INDEX |
493 HTON_PARTIAL_COLUMN_READ |
494 HTON_TABLE_SCAN_ON_INDEX |
495 HTON_HAS_FOREIGN_KEYS |
496 HTON_HAS_DOES_TRANSACTIONS)
498 ENGINE_NEW_STATE(
"::SEAPITester()");
503 ENGINE_NEW_STATE(
"::~SEAPITester()");
507 return api_tester_exts;
513 Cursor *realCursor= getRealEngine()->create(table);
514 c->realCursor= realCursor;
529 {
return getRealEngine()->renameTable(session, from, to); }
531 int doGetTableDefinition(
Session& ,
539 drizzled::identifier::table::vector &);
541 virtual int doStartTransaction(
Session *session,
542 start_transaction_option_t options);
543 virtual void doStartStatement(
Session *session);
544 virtual void doEndStatement(
Session *session);
549 ENGINE_NEW_STATE(
"SET SAVEPOINT");
550 ENGINE_NEW_STATE(
"In Transaction");
552 virtual int doRollbackToSavepoint(
Session*,
555 ENGINE_NEW_STATE(
"ROLLBACK TO SAVEPOINT");
556 ENGINE_NEW_STATE(
"In Transaction");
558 virtual int doReleaseSavepoint(
Session*,
561 ENGINE_NEW_STATE(
"RELEASE SAVEPOINT");
562 ENGINE_NEW_STATE(
"In Transaction");
564 virtual int doCommit(
Session*,
bool);
566 virtual int doRollback(
Session*,
bool);
568 uint32_t max_supported_record_length(
void)
const {
569 ENGINE_NEW_STATE(
"::max_supported_record_length()");
570 return getRealEngine()->max_supported_record_length();
573 uint32_t max_supported_keys(
void)
const {
574 ENGINE_NEW_STATE(
"::max_supported_keys()");
575 return getRealEngine()->max_supported_keys();
578 uint32_t max_supported_key_parts(
void)
const {
579 ENGINE_NEW_STATE(
"::max_supported_key_parts()");
580 return getRealEngine()->max_supported_key_parts();
583 uint32_t max_supported_key_length(
void)
const {
584 ENGINE_NEW_STATE(
"::max_supported_key_length()");
585 return getRealEngine()->max_supported_key_length();
588 uint32_t max_supported_key_part_length(
void)
const {
589 ENGINE_NEW_STATE(
"::max_supported_key_part_length()");
590 return getRealEngine()->max_supported_key_part_length();
594 uint32_t index_flags(
enum ha_key_alg)
const
596 return (HA_READ_NEXT |
607 return getRealEngine()->doDoesTableExist(session, identifier);
612 drizzled::identifier::table::vector &ti)
614 return getRealEngine()->doGetTableIdentifiers(cd, si, ti);
617 int SEAPITester::doCreateTable(
Session& session,
622 ENGINE_NEW_STATE(
"::doCreateTable()");
624 int r= getRealEngine()->doCreateTable(session, table, identifier, create_proto);
626 ENGINE_NEW_STATE(
"::SEAPITester()");
632 return getRealEngine()->doDropTable(session, identifier);
635 int SEAPITester::doGetTableDefinition(
Session& session,
639 return getRealEngine()->doGetTableDefinition(session, identifier, table);
642 int SEAPITester::doStartTransaction(
Session *session,
643 start_transaction_option_t opt)
645 ENGINE_NEW_STATE(
"BEGIN");
646 ENGINE_NEW_STATE(
"In Transaction");
648 return getRealEngine()->startTransaction(session, opt);
651 void SEAPITester::doStartStatement(
Session *session)
653 ENGINE_NEW_STATE(
"START STATEMENT");
654 return getRealEngine()->startStatement(session);
657 void SEAPITester::doEndStatement(
Session *session)
659 ENGINE_NEW_STATE(
"END STATEMENT");
660 return getRealEngine()->endStatement(session);
663 int SEAPITester::doCommit(
Session *session,
bool all)
667 ENGINE_NEW_STATE(
"COMMIT");
668 ENGINE_NEW_STATE(
"::SEAPITester()");
672 ENGINE_NEW_STATE(
"COMMIT STATEMENT");
673 ENGINE_NEW_STATE(
"In Transaction");
675 return getRealEngine()->commit(session, all);
678 int SEAPITester::doRollback(
Session *session,
bool all)
682 ENGINE_NEW_STATE(
"ROLLBACK");
683 ENGINE_NEW_STATE(
"::SEAPITester()");
687 ENGINE_NEW_STATE(
"ROLLBACK STATEMENT");
688 ENGINE_NEW_STATE(
"In Transaction");
691 return getRealEngine()->rollback(session, all);
699 load_engine_state_transitions(engine_state_transitions);
700 load_cursor_state_transitions(cursor_state_transitions);
701 engine_state=
"INIT";
703 context.add(
new plugin::SEAPITester(engine_name));
705 context.add(
new plugin::Create_function<SEAPITesterErrorInjectFunc>(
"seapitester_error_inject"));
707 engine_state_history_table_initialize(context);
712 DRIZZLE_DECLARE_PLUGIN
718 N_(
"StorageEngine module for testing call order"),
724 DRIZZLE_DECLARE_PLUGIN_END;