00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include <config.h>
00020 #include <drizzled/table.h>
00021 #include <drizzled/error.h>
00022 #include <drizzled/plugin/transactional_storage_engine.h>
00023 #include <drizzled/session.h>
00024 #include <string>
00025 #include <map>
00026 #include <fstream>
00027 #include <drizzled/message/table.pb.h>
00028 #include <drizzled/internal/m_string.h>
00029
00030 #include <drizzled/global_charset_info.h>
00031
00032 #include <boost/unordered_map.hpp>
00033
00034 #include "engine_state_history.h"
00035
00036 using namespace std;
00037 using namespace drizzled;
00038
00039 string engine_state;
00040
00041 typedef multimap<string, string> state_multimap;
00042 typedef multimap<string, string>::value_type state_pair;
00043 typedef multimap<string, string>::iterator state_multimap_iter;
00044 state_multimap engine_state_transitions;
00045 state_multimap cursor_state_transitions;
00046
00047 void load_engine_state_transitions(state_multimap &states);
00048 void load_cursor_state_transitions(state_multimap &states);
00049
00050 plugin::TransactionalStorageEngine *realEngine;
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068 static uint32_t error_injected= 0;
00069
00070 #include <drizzled/function/math/int.h>
00071 #include <drizzled/plugin/function.h>
00072
00073 class SEAPITesterErrorInjectFunc :public Item_int_func
00074 {
00075 public:
00076 int64_t val_int();
00077 SEAPITesterErrorInjectFunc() :Item_int_func() {}
00078
00079 const char *func_name() const
00080 {
00081 return "seapitester_error_inject";
00082 }
00083
00084 void fix_length_and_dec()
00085 {
00086 max_length= 4;
00087 }
00088
00089 bool check_argument_count(int n)
00090 {
00091 return (n == 1);
00092 }
00093 };
00094
00095
00096 int64_t SEAPITesterErrorInjectFunc::val_int()
00097 {
00098 assert(fixed == true);
00099 uint32_t err_to_inject= args[0]->val_int();
00100
00101 error_injected= err_to_inject;
00102
00103 return error_injected;
00104 }
00105
00106 static plugin::TransactionalStorageEngine *getRealEngine()
00107 {
00108 return down_cast<plugin::TransactionalStorageEngine*>(plugin::StorageEngine::findByName("INNODB"));
00109 }
00110
00111 static inline void ENGINE_NEW_STATE(const string &new_state)
00112 {
00113 state_multimap_iter cur= engine_state_transitions.find(engine_state);
00114 if (engine_state_transitions.count(engine_state) == 0)
00115 {
00116 cerr << "ERROR: Invalid engine state: " << engine_state << endl
00117 << "This should *NEVER* happen."
00118 << endl
00119 << "i.e. you've really screwed it up and you should be ashamed of "
00120 << "yourself." << endl;
00121 assert(engine_state_transitions.count(engine_state));
00122 }
00123
00124 for(cur= engine_state_transitions.lower_bound(engine_state);
00125 cur != engine_state_transitions.upper_bound(engine_state);
00126 cur++)
00127 {
00128 if (new_state.compare((*cur).second) == 0)
00129 break;
00130 }
00131
00132 if (cur == engine_state_transitions.end()
00133 || new_state.compare((*cur).second))
00134 {
00135 cerr << "ERROR: Invalid Storage Engine state transition!" << endl
00136 << "Cannot go from " << engine_state << " to " << new_state << endl;
00137 assert(false);
00138 }
00139
00140 engine_state= new_state;
00141 engine_state_history.push_back(new_state);
00142
00143 cerr << "\tENGINE STATE : " << engine_state << endl;
00144 }
00145
00146 static const string engine_name("STORAGE_ENGINE_API_TESTER");
00147 namespace drizzled {
00148 class SEAPITesterCursor : public drizzled::Cursor
00149 {
00150 friend class drizzled::Cursor;
00151 public:
00152 drizzled::Cursor *realCursor;
00153
00154 SEAPITesterCursor(drizzled::plugin::StorageEngine &engine_arg,
00155 drizzled::Table &table_arg)
00156 : Cursor(engine_arg, table_arg)
00157 { cursor_state= "Cursor()"; realCursor= NULL;}
00158
00159 ~SEAPITesterCursor()
00160 { delete realCursor;}
00161
00162 int close();
00163 int rnd_next(unsigned char *buf) {
00164 static int count= 0;
00165 CURSOR_NEW_STATE("::rnd_next()");
00166
00167 if (error_injected == 3 && (count++ % 2))
00168 {
00169 user_session->markTransactionForRollback(false);
00170 return HA_ERR_LOCK_WAIT_TIMEOUT;
00171 }
00172 return realCursor->rnd_next(buf);
00173 }
00174
00175 int rnd_pos(unsigned char* buf, unsigned char* pos) { CURSOR_NEW_STATE("::rnd_pos()"); return realCursor->rnd_pos(buf, pos); }
00176 void position(const unsigned char *record);
00177 int info(uint32_t flag);
00178
00179 int reset();
00180
00181 void get_auto_increment(uint64_t, uint64_t, uint64_t, uint64_t*, uint64_t*) {}
00182 int doStartTableScan(bool scan) { CURSOR_NEW_STATE("::doStartTableScan()"); return realCursor->doStartTableScan(scan); }
00183 int doEndTableScan() { CURSOR_NEW_STATE("::doEndTableScan()"); return realCursor->doEndTableScan(); }
00184
00185 const char *index_type(uint32_t key_number);
00186
00187 int doStartIndexScan(uint32_t, bool);
00188 int index_read(unsigned char *buf, const unsigned char *key_ptr,
00189 uint32_t key_len, drizzled::ha_rkey_function find_flag);
00190 int index_read_idx_map(unsigned char * buf,
00191 uint32_t index,
00192 const unsigned char * key,
00193 drizzled::key_part_map keypart_map,
00194 drizzled::ha_rkey_function find_flag);
00195
00196 int index_next(unsigned char * buf);
00197 int doEndIndexScan();
00198 int index_prev(unsigned char * buf);
00199 int index_first(unsigned char * buf);
00200 int index_last(unsigned char * buf);
00201
00202 bool primary_key_is_clustered()
00203 {
00204 return realCursor->primary_key_is_clustered();
00205 }
00206
00207
00208 int doOpen(const identifier::Table &identifier, int mode, uint32_t test_if_locked);
00209
00210 THR_LOCK_DATA **store_lock(Session *,
00211 THR_LOCK_DATA **to,
00212 enum thr_lock_type);
00213
00214 int external_lock(Session *session, int lock_type);
00215
00216 int doInsertRecord(unsigned char *buf)
00217 {
00218 static int i=0;
00219 CURSOR_NEW_STATE("::doInsertRecord()");
00220
00221 if (error_injected == 1 && (i++ % 2))
00222 {
00223 user_session->markTransactionForRollback(false);
00224 return HA_ERR_LOCK_WAIT_TIMEOUT;
00225 }
00226
00227 if (error_injected == 2 && (i++ % 2))
00228 {
00229 user_session->markTransactionForRollback(true);
00230 return HA_ERR_LOCK_DEADLOCK;
00231 }
00232
00233 return realCursor->doInsertRecord(buf);
00234 }
00235
00236 int doUpdateRecord(const unsigned char *old_row, unsigned char *new_row)
00237 {
00238 CURSOR_NEW_STATE("::doUpdateRecord()");
00239 return realCursor->doUpdateRecord(old_row, new_row);
00240 }
00241
00242 double scan_time()
00243 {
00244 CURSOR_NEW_STATE("::scan_time()");
00245 CURSOR_NEW_STATE("locked");
00246 return realCursor->scan_time();
00247 }
00248
00249 int extra(enum ha_extra_function operation)
00250 {
00251 return realCursor->extra(operation);
00252 }
00253
00254 private:
00255 string cursor_state;
00256 void CURSOR_NEW_STATE(const string &new_state);
00257 Session* user_session;
00258 };
00259
00260 int SEAPITesterCursor::doOpen(const identifier::Table &identifier, int mode, uint32_t test_if_locked)
00261 {
00262 CURSOR_NEW_STATE("::doOpen()");
00263
00264 int r= realCursor->doOpen(identifier, mode, test_if_locked);
00265
00266 ref_length= realCursor->ref_length;
00267
00268 return r;
00269 }
00270
00271 int SEAPITesterCursor::reset()
00272 {
00273 CURSOR_NEW_STATE("::reset()");
00274 CURSOR_NEW_STATE("::doOpen()");
00275
00276 return realCursor->reset();
00277 }
00278
00279 int SEAPITesterCursor::close()
00280 {
00281 CURSOR_NEW_STATE("::close()");
00282 CURSOR_NEW_STATE("Cursor()");
00283
00284 return realCursor->close();
00285 }
00286
00287 void SEAPITesterCursor::position(const unsigned char *record)
00288 {
00289 CURSOR_NEW_STATE("::position()");
00290
00291
00292 realCursor->ref= ref;
00293
00294 realCursor->position(record);
00295 }
00296
00297 int SEAPITesterCursor::info(uint32_t flag)
00298 {
00299 int r;
00300 CURSOR_NEW_STATE("::info()");
00301 CURSOR_NEW_STATE("locked");
00302
00303 r= realCursor->info(flag);
00304
00305 if (flag & (HA_STATUS_VARIABLE|HA_STATUS_AUTO|HA_STATUS_CONST))
00306 {
00307 stats= realCursor->stats;
00308 }
00309
00310 if (flag & HA_STATUS_ERRKEY)
00311 errkey= realCursor->errkey;
00312
00313 return r;
00314 }
00315
00316 const char * SEAPITesterCursor::index_type(uint32_t key_number)
00317 {
00318 CURSOR_NEW_STATE("::index_type()");
00319 return realCursor->index_type(key_number);
00320 }
00321
00322 int SEAPITesterCursor::doStartIndexScan(uint32_t keynr, bool scan)
00323 {
00324 int r;
00325 CURSOR_NEW_STATE("::doStartIndexScan()");
00326
00327 if (error_injected == 4)
00328 {
00329 CURSOR_NEW_STATE("::doStartIndexScan() ERROR");
00330 CURSOR_NEW_STATE("locked");
00331 return HA_ERR_LOCK_DEADLOCK;
00332 }
00333
00334 r= realCursor->doStartIndexScan(keynr, scan);
00335
00336 active_index= realCursor->get_index();
00337
00338 return r;
00339 }
00340
00341 int SEAPITesterCursor::index_read(unsigned char *buf,
00342 const unsigned char *key_ptr,
00343 uint32_t key_len,
00344 drizzled::ha_rkey_function find_flag)
00345 {
00346 CURSOR_NEW_STATE("::index_read()");
00347 CURSOR_NEW_STATE("::doStartIndexScan()");
00348 return realCursor->index_read(buf, key_ptr, key_len, find_flag);
00349 }
00350
00351 int SEAPITesterCursor::index_read_idx_map(unsigned char * buf,
00352 uint32_t index,
00353 const unsigned char * key,
00354 drizzled::key_part_map keypart_map,
00355 drizzled::ha_rkey_function find_flag)
00356 {
00357 CURSOR_NEW_STATE("::index_read_idx_map()");
00358 CURSOR_NEW_STATE("locked");
00359 return realCursor->index_read_idx_map(buf, index, key, keypart_map, find_flag);
00360 }
00361
00362 int SEAPITesterCursor::index_next(unsigned char * buf)
00363 {
00364 CURSOR_NEW_STATE("::index_next()");
00365 CURSOR_NEW_STATE("::doStartIndexScan()");
00366 return realCursor->index_next(buf);
00367 }
00368
00369 int SEAPITesterCursor::doEndIndexScan()
00370 {
00371 CURSOR_NEW_STATE("::doEndIndexScan()");
00372 CURSOR_NEW_STATE("locked");
00373 int r= realCursor->doEndIndexScan();
00374
00375 active_index= realCursor->get_index();
00376
00377 return r;
00378 }
00379
00380 int SEAPITesterCursor::index_prev(unsigned char * buf)
00381 {
00382 CURSOR_NEW_STATE("::index_prev()");
00383 CURSOR_NEW_STATE("::doStartIndexScan()");
00384 return realCursor->index_prev(buf);
00385 }
00386
00387 int SEAPITesterCursor::index_first(unsigned char * buf)
00388 {
00389 CURSOR_NEW_STATE("::index_first()");
00390 CURSOR_NEW_STATE("::doStartIndexScan()");
00391 return realCursor->index_first(buf);
00392 }
00393
00394 int SEAPITesterCursor::index_last(unsigned char * buf)
00395 {
00396 CURSOR_NEW_STATE("::index_last()");
00397 CURSOR_NEW_STATE("::doStartIndexScan()");
00398 return realCursor->index_last(buf);
00399 }
00400
00401 int SEAPITesterCursor::external_lock(Session *session, int lock_type)
00402 {
00403 CURSOR_NEW_STATE("::external_lock()");
00404 CURSOR_NEW_STATE("locked");
00405
00406 user_session= session;
00407
00408 return realCursor->external_lock(session, lock_type);
00409 }
00410
00411 THR_LOCK_DATA **SEAPITesterCursor::store_lock(Session *session,
00412 THR_LOCK_DATA **to,
00413 enum thr_lock_type lock_type)
00414
00415 {
00416 CURSOR_NEW_STATE("::store_lock()");
00417
00418 return realCursor->store_lock(session, to, lock_type);
00419 }
00420
00421 void SEAPITesterCursor::CURSOR_NEW_STATE(const string &new_state)
00422 {
00423 state_multimap_iter cur= cursor_state_transitions.find(cursor_state);
00424 if (cursor_state_transitions.count(cursor_state) == 0)
00425 {
00426 cerr << "ERROR: Invalid Cursor state: " << cursor_state << endl
00427 << "This should *NEVER* happen."
00428 << endl
00429 << "i.e. you've really screwed it up and you should be ashamed of "
00430 << "yourself." << endl;
00431 assert(cursor_state_transitions.count(cursor_state));
00432 }
00433
00434 for(cur= cursor_state_transitions.lower_bound(cursor_state);
00435 cur != cursor_state_transitions.upper_bound(cursor_state);
00436 cur++)
00437 {
00438 if (new_state.compare((*cur).second) == 0)
00439 break;
00440 }
00441
00442 if (cur == cursor_state_transitions.end()
00443 || new_state.compare((*cur).second))
00444 {
00445 cerr << "ERROR: Invalid Cursor state transition!" << endl
00446 << "Cursor " << this << "Cannot go from "
00447 << cursor_state << " to " << new_state << endl;
00448 assert(false);
00449 }
00450
00451 cursor_state= new_state;
00452
00453 cerr << "\t\tCursor " << this << " STATE : " << cursor_state << endl;
00454 }
00455
00456 }
00457
00458 static const char *api_tester_exts[] = {
00459 NULL
00460 };
00461
00462 namespace drizzled {
00463 namespace plugin {
00464 class SEAPITester : public drizzled::plugin::TransactionalStorageEngine
00465 {
00466 public:
00467
00468
00469
00470 SEAPITester(const string &name_arg)
00471 : drizzled::plugin::TransactionalStorageEngine(name_arg,
00472 HTON_NULL_IN_KEY |
00473 HTON_CAN_INDEX_BLOBS |
00474 HTON_PRIMARY_KEY_IN_READ_INDEX |
00475 HTON_PARTIAL_COLUMN_READ |
00476 HTON_TABLE_SCAN_ON_INDEX |
00477 HTON_HAS_FOREIGN_KEYS |
00478 HTON_HAS_DOES_TRANSACTIONS)
00479 {
00480 ENGINE_NEW_STATE("::SEAPITester()");
00481 }
00482
00483 ~SEAPITester()
00484 {
00485 ENGINE_NEW_STATE("::~SEAPITester()");
00486 }
00487
00488 const char **bas_ext() const {
00489 return api_tester_exts;
00490 }
00491
00492 virtual Cursor *create(Table &table)
00493 {
00494 SEAPITesterCursor *c= new SEAPITesterCursor(*this, table);
00495 Cursor *realCursor= getRealEngine()->create(table);
00496 c->realCursor= realCursor;
00497
00498 return c;
00499 }
00500
00501 int doCreateTable(Session&,
00502 Table&,
00503 const drizzled::identifier::Table &identifier,
00504 const drizzled::message::Table& create_proto);
00505
00506 int doDropTable(Session&, const identifier::Table &identifier);
00507
00508 int doRenameTable(drizzled::Session& session,
00509 const drizzled::identifier::Table& from,
00510 const drizzled::identifier::Table& to)
00511 { return getRealEngine()->renameTable(session, from, to); }
00512
00513 int doGetTableDefinition(Session& ,
00514 const identifier::Table &,
00515 drizzled::message::Table &);
00516
00517 bool doDoesTableExist(Session&, const identifier::Table &identifier);
00518
00519 void doGetTableIdentifiers(drizzled::CachedDirectory &,
00520 const drizzled::identifier::Schema &,
00521 drizzled::identifier::Table::vector &);
00522
00523 virtual int doStartTransaction(Session *session,
00524 start_transaction_option_t options);
00525 virtual void doStartStatement(Session *session);
00526 virtual void doEndStatement(Session *session);
00527
00528 virtual int doSetSavepoint(Session*,
00529 drizzled::NamedSavepoint &)
00530 {
00531 ENGINE_NEW_STATE("SET SAVEPOINT");
00532 ENGINE_NEW_STATE("In Transaction");
00533 return 0; }
00534 virtual int doRollbackToSavepoint(Session*,
00535 drizzled::NamedSavepoint &)
00536 {
00537 ENGINE_NEW_STATE("ROLLBACK TO SAVEPOINT");
00538 ENGINE_NEW_STATE("In Transaction");
00539 return 0; }
00540 virtual int doReleaseSavepoint(Session*,
00541 drizzled::NamedSavepoint &)
00542 {
00543 ENGINE_NEW_STATE("RELEASE SAVEPOINT");
00544 ENGINE_NEW_STATE("In Transaction");
00545 return 0; }
00546 virtual int doCommit(Session*, bool);
00547
00548 virtual int doRollback(Session*, bool);
00549
00550 uint32_t max_supported_record_length(void) const {
00551 ENGINE_NEW_STATE("::max_supported_record_length()");
00552 return getRealEngine()->max_supported_record_length();
00553 }
00554
00555 uint32_t max_supported_keys(void) const {
00556 ENGINE_NEW_STATE("::max_supported_keys()");
00557 return getRealEngine()->max_supported_keys();
00558 }
00559
00560 uint32_t max_supported_key_parts(void) const {
00561 ENGINE_NEW_STATE("::max_supported_key_parts()");
00562 return getRealEngine()->max_supported_key_parts();
00563 }
00564
00565 uint32_t max_supported_key_length(void) const {
00566 ENGINE_NEW_STATE("::max_supported_key_length()");
00567 return getRealEngine()->max_supported_key_length();
00568 }
00569
00570 uint32_t max_supported_key_part_length(void) const {
00571 ENGINE_NEW_STATE("::max_supported_key_part_length()");
00572 return getRealEngine()->max_supported_key_part_length();
00573 }
00574
00575
00576 uint32_t index_flags(enum ha_key_alg) const
00577 {
00578 return (HA_READ_NEXT |
00579 HA_READ_PREV |
00580 HA_READ_RANGE |
00581 HA_READ_ORDER |
00582 HA_KEYREAD_ONLY);
00583 }
00584
00585 };
00586
00587 bool SEAPITester::doDoesTableExist(Session &session, const identifier::Table &identifier)
00588 {
00589 return getRealEngine()->doDoesTableExist(session, identifier);
00590 }
00591
00592 void SEAPITester::doGetTableIdentifiers(drizzled::CachedDirectory &cd,
00593 const drizzled::identifier::Schema &si,
00594 drizzled::identifier::Table::vector &ti)
00595 {
00596 return getRealEngine()->doGetTableIdentifiers(cd, si, ti);
00597 }
00598
00599 int SEAPITester::doCreateTable(Session& session,
00600 Table& table,
00601 const drizzled::identifier::Table &identifier,
00602 const drizzled::message::Table& create_proto)
00603 {
00604 ENGINE_NEW_STATE("::doCreateTable()");
00605
00606 int r= getRealEngine()->doCreateTable(session, table, identifier, create_proto);
00607
00608 ENGINE_NEW_STATE("::SEAPITester()");
00609 return r;
00610 }
00611
00612 int SEAPITester::doDropTable(Session& session, const identifier::Table &identifier)
00613 {
00614 return getRealEngine()->doDropTable(session, identifier);
00615 }
00616
00617 int SEAPITester::doGetTableDefinition(Session& session,
00618 const identifier::Table &identifier,
00619 drizzled::message::Table &table)
00620 {
00621 return getRealEngine()->doGetTableDefinition(session, identifier, table);
00622 }
00623
00624 int SEAPITester::doStartTransaction(Session *session,
00625 start_transaction_option_t opt)
00626 {
00627 ENGINE_NEW_STATE("BEGIN");
00628 ENGINE_NEW_STATE("In Transaction");
00629
00630 return getRealEngine()->startTransaction(session, opt);
00631 }
00632
00633 void SEAPITester::doStartStatement(Session *session)
00634 {
00635 ENGINE_NEW_STATE("START STATEMENT");
00636 return getRealEngine()->startStatement(session);
00637 }
00638
00639 void SEAPITester::doEndStatement(Session *session)
00640 {
00641 ENGINE_NEW_STATE("END STATEMENT");
00642 return getRealEngine()->endStatement(session);
00643 }
00644
00645 int SEAPITester::doCommit(Session *session, bool all)
00646 {
00647 if (all)
00648 {
00649 ENGINE_NEW_STATE("COMMIT");
00650 ENGINE_NEW_STATE("::SEAPITester()");
00651 }
00652 else
00653 {
00654 ENGINE_NEW_STATE("COMMIT STATEMENT");
00655 ENGINE_NEW_STATE("In Transaction");
00656 }
00657 return getRealEngine()->commit(session, all);
00658 }
00659
00660 int SEAPITester::doRollback(Session *session, bool all)
00661 {
00662 if (all)
00663 {
00664 ENGINE_NEW_STATE("ROLLBACK");
00665 ENGINE_NEW_STATE("::SEAPITester()");
00666 }
00667 else
00668 {
00669 ENGINE_NEW_STATE("ROLLBACK STATEMENT");
00670 ENGINE_NEW_STATE("In Transaction");
00671 }
00672
00673 return getRealEngine()->rollback(session, all);
00674 }
00675
00676 }
00677 }
00678
00679 static int seapi_tester_init(drizzled::module::Context &context)
00680 {
00681 load_engine_state_transitions(engine_state_transitions);
00682 load_cursor_state_transitions(cursor_state_transitions);
00683 engine_state= "INIT";
00684
00685 context.add(new plugin::SEAPITester(engine_name));
00686
00687 context.add(new plugin::Create_function<SEAPITesterErrorInjectFunc>("seapitester_error_inject"));
00688
00689 engine_state_history_table_initialize(context);
00690
00691 return 0;
00692 }
00693
00694 DRIZZLE_DECLARE_PLUGIN
00695 {
00696 DRIZZLE_VERSION_ID,
00697 "SEAPITESTER",
00698 "1.0",
00699 "Stewart Smith",
00700 "Test the Storage Engine API callls are in correct order",
00701 PLUGIN_LICENSE_GPL,
00702 seapi_tester_init,
00703 NULL,
00704 NULL
00705 }
00706 DRIZZLE_DECLARE_PLUGIN_END;