Drizzled Public API Documentation

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