Drizzled Public API Documentation

engine_ms.cc

00001 /* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
00002  *
00003  * PrimeBase Media Stream for MySQL
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00018  *
00019  * Original author: Paul McCullagh
00020  * Continued development: Barry Leslie
00021  *
00022  * 2007-07-20
00023  *
00024  * H&G2JCtL
00025  *
00026  * Engine interface.
00027  *
00028  */
00029 #ifdef DRIZZLED
00030 #include <config.h>
00031 
00032 #include <drizzled/common.h>
00033 #include <drizzled/current_session.h>
00034 #include <drizzled/session.h>
00035 #endif
00036 
00037 
00038 #include "cslib/CSConfig.h"
00039 #include "cslib/CSGlobal.h"
00040 #include "cslib/CSStrUtil.h"
00041 #include "cslib/CSThread.h"
00042 
00043 #ifndef DRIZZLED
00044 #define PBMS_API pbms_internal  
00045 #include "pbms.h"
00046 #endif
00047 
00048 #include "engine_ms.h"
00049 #include "connection_handler_ms.h"
00050 #include "open_table_ms.h"
00051 #include "network_ms.h"
00052 #include "transaction_ms.h"
00053 #include "mysql_ms.h"
00054 
00055 
00056 #ifdef new
00057 #undef new
00058 #endif
00059 
00060 // From ha-pbms.cc:
00061 extern CSThread *pbms_getMySelf(THD *thd);
00062 extern void pbms_setMySelf(THD *thd, CSThread *self);
00063 
00064 #ifndef DRIZZLED
00065 
00066 /*
00067  * ---------------------------------------------------------------
00068  * ENGINE CALL-IN INTERFACE
00069  */
00070 
00071 static PBMS_API *StreamingEngines;
00072 // If PBMS support is built directly into the mysql/drizzle handler code 
00073 // then calls from all other handlers are ignored.
00074 static bool have_handler_support = false; 
00075 
00076 /*
00077  * ---------------------------------------------------------------
00078  * ENGINE CALLBACK INTERFACE
00079  */
00080 
00081 static void ms_register_engine(PBMSEnginePtr engine)
00082 {
00083   if (engine->ms_internal)
00084     have_handler_support = true;
00085 }
00086 
00087 static void ms_deregister_engine(PBMSEnginePtr engine)
00088 {
00089   UNUSED(engine);
00090 }
00091 
00092 static int ms_create_blob(bool internal, const char *db_name, const char *tab_name, char *blob, size_t blob_len, PBMSBlobURLPtr blob_url, PBMSResultPtr result)
00093 {
00094   if (have_handler_support && !internal) {
00095     MSEngine::errorResult(CS_CONTEXT, MS_ERR_INVALID_OPERATION, "Invalid ms_create_blob() call", result);
00096     return MS_ERR_ENGINE;
00097   }
00098 
00099   return MSEngine::createBlob(db_name, tab_name, blob, blob_len, blob_url, result);
00100 }
00101 
00102 /*
00103  * ms_use_blob() may or may not alter the blob url depending on the type of URL and if the BLOB is in a
00104  * different database or not. It may also add a BLOB reference to the BLOB table log if the BLOB was from
00105  * a different table or no table was specified when the BLOB was uploaded.
00106  *
00107  * There is no need to undo this function because it will be undone automaticly if the BLOB is not retained.
00108  */
00109 static int ms_retain_blob(bool internal, const char *db_name, const char *tab_name, PBMSBlobURLPtr ret_blob_url, char *blob_url, unsigned short col_index, PBMSResultPtr result)
00110 {
00111   if (have_handler_support && !internal) {
00112     cs_strcpy(PBMS_BLOB_URL_SIZE, ret_blob_url->bu_data, blob_url); // This should have already been converted.
00113     return MS_OK;
00114   }
00115   
00116   return MSEngine::referenceBlob(db_name, tab_name, ret_blob_url, blob_url, col_index, result); 
00117 }
00118 
00119 static int ms_release_blob(bool internal, const char *db_name, const char *tab_name, char *blob_url, PBMSResultPtr result)
00120 {
00121 
00122   if (have_handler_support && !internal) 
00123     return MS_OK;
00124   
00125   return MSEngine::dereferenceBlob(db_name, tab_name, blob_url, result);  
00126 }
00127 
00128 static int ms_drop_table(bool internal, const char *db_name, const char *tab_name, PBMSResultPtr result)
00129 {
00130   if (have_handler_support && !internal) 
00131     return MS_OK;
00132 
00133   return MSEngine::dropTable(db_name, tab_name, result);  
00134 }
00135 
00136 static int ms_rename_table(bool internal, const char * db_name, const char *from_table, const char *to_db, const char *to_table, PBMSResultPtr result)
00137 {
00138   if (have_handler_support && !internal) 
00139     return MS_OK;
00140 
00141   return MSEngine::renameTable(db_name, from_table, to_db, to_table, result); 
00142 }
00143 
00144 static void ms_completed(bool internal, bool ok)
00145 {
00146   if (have_handler_support && !internal) 
00147     return;
00148     
00149   MSEngine::callCompleted(ok);  
00150 }
00151 
00152 PBMSCallbacksRec engine_callbacks = {
00153   MS_CALLBACK_VERSION,
00154   ms_register_engine,
00155   ms_deregister_engine,
00156   ms_create_blob,
00157   ms_retain_blob,
00158   ms_release_blob,
00159   ms_drop_table,
00160   ms_rename_table,
00161   ms_completed
00162 };
00163 
00164 // =============================
00165 int MSEngine::startUp(PBMSResultPtr result)
00166 {
00167   int err = 0;
00168   
00169   StreamingEngines = new PBMS_API();
00170   err = StreamingEngines->PBMSStartup(&engine_callbacks, result);
00171   if (err)
00172     delete StreamingEngines;
00173   else { // Register the PBMS enabled engines the startup before PBMS
00174     PBMSSharedMemoryPtr   sh_mem = StreamingEngines->sharedMemory;
00175     PBMSEnginePtr     engine;
00176     
00177     for (int i=0; i<sh_mem->sm_list_len; i++) {
00178       if ((engine = sh_mem->sm_engine_list[i])) 
00179         ms_register_engine(engine);
00180     }
00181   }
00182   return err;
00183 }
00184 
00185 void MSEngine::shutDown()
00186 {
00187   StreamingEngines->PBMSShutdown();
00188 
00189   delete StreamingEngines;
00190 }
00191 
00192 const PBMSEnginePtr MSEngine::getEngineInfoAt(int indx)
00193 {
00194   PBMSSharedMemoryPtr   sh_mem = StreamingEngines->sharedMemory;
00195   PBMSEnginePtr     engine = NULL;
00196   
00197   if (sh_mem) {
00198     for (int i=0; i<sh_mem->sm_list_len; i++) {
00199       if ((engine = sh_mem->sm_engine_list[i])) {
00200         if (!indx)
00201           return engine;
00202         indx--;
00203       }
00204     }
00205   }
00206   
00207   return (const PBMSEnginePtr)NULL;
00208 }
00209 #endif  
00210 
00211 //---------------
00212 bool MSEngine::try_createBlob(CSThread *self, const char *db_name, const char *tab_name, char *blob, size_t blob_len, PBMSBlobURLPtr blob_url)
00213 {
00214   volatile bool rtc = true;
00215   
00216   try_(a) {
00217     MSOpenTable   *otab;
00218     CSInputStream *i_stream = NULL;
00219     
00220     otab = openTable(db_name, tab_name, true);
00221     frompool_(otab);
00222     
00223     if (!otab->getDB()->isRecovering()) {
00224       i_stream = CSMemoryInputStream::newStream((unsigned char *)blob, blob_len);
00225       otab->createBlob(blob_url, blob_len, NULL, 0, i_stream);
00226     } else
00227       CSException::throwException(CS_CONTEXT, MS_ERR_RECOVERY_IN_PROGRESS, "Cannot create BLOBs during repository recovery.");
00228 
00229     backtopool_(otab);
00230     rtc = false;      
00231   }
00232   catch_(a);
00233   cont_(a);
00234   return rtc;
00235 }
00236 
00237 //---------------
00238 int32_t MSEngine::createBlob(const char *db_name, const char *tab_name, char *blob, size_t blob_len, PBMSBlobURLPtr blob_url, PBMSResultPtr result)
00239 {
00240 
00241   CSThread    *self;
00242   int32_t     err = MS_OK;
00243   
00244   if ((err = enterConnectionNoThd(&self, result)))
00245     return err;
00246 
00247   inner_();
00248   if (try_createBlob(self, db_name, tab_name, blob, blob_len, blob_url))
00249     err = exceptionToResult(&self->myException, result);
00250 
00251   return_(err);
00252 }
00253 
00254 //---------------
00255 bool MSEngine::try_referenceBlob(CSThread *self, const char *db_name, const char *tab_name, PBMSBlobURLPtr ret_blob_url, char *blob_url, uint16_t col_index)
00256 {
00257   volatile bool rtc = true;
00258   try_(a) {
00259     MSBlobURLRec  blob;
00260     MSOpenTable   *otab;
00261     
00262     if (! PBMSBlobURLTools::couldBeURL(blob_url, &blob)){
00263       char buffer[CS_EXC_MESSAGE_SIZE];
00264       
00265       cs_strcpy(CS_EXC_MESSAGE_SIZE, buffer, "Incorrect URL: ");
00266       cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, blob_url);
00267       CSException::throwException(CS_CONTEXT, MS_ERR_INCORRECT_URL, buffer);
00268     }
00269     
00270     otab = openTable(db_name, tab_name, true);
00271     frompool_(otab);
00272 
00273     otab->useBlob(blob.bu_type, blob.bu_db_id, blob.bu_tab_id, blob.bu_blob_id, blob.bu_auth_code, col_index, blob.bu_blob_size, blob.bu_blob_ref_id, ret_blob_url);
00274 
00275     backtopool_(otab);
00276     rtc = false;      
00277   }
00278   catch_(a);
00279   cont_(a);
00280   return rtc;
00281 }
00282 
00283 //---------------
00284 int32_t MSEngine::referenceBlob(const char *db_name, const char *tab_name, PBMSBlobURLPtr ret_blob_url, char *blob_url, uint16_t col_index, PBMSResultPtr result)
00285 {
00286 
00287   CSThread    *self;
00288   int32_t     err = MS_OK;
00289   
00290   if ((err = enterConnectionNoThd(&self, result)))
00291     return err;
00292 
00293   inner_();
00294   if (try_referenceBlob(self, db_name, tab_name, ret_blob_url, blob_url, col_index))
00295     err = exceptionToResult(&self->myException, result);
00296 
00297   return_(err);
00298 
00299 }
00300 
00301 //---------------
00302 bool MSEngine::try_dereferenceBlob(CSThread *self, const char *db_name, const char *tab_name, char *blob_url)
00303 {
00304   volatile bool rtc = true;
00305   try_(a) {
00306     MSBlobURLRec  blob;
00307     MSOpenTable   *otab;
00308 
00309     if (! PBMSBlobURLTools::couldBeURL(blob_url, &blob)){
00310       char buffer[CS_EXC_MESSAGE_SIZE];
00311 
00312       cs_strcpy(CS_EXC_MESSAGE_SIZE, buffer, "Incorrect URL: ");
00313       cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, blob_url);
00314       CSException::throwException(CS_CONTEXT, MS_ERR_INCORRECT_URL, buffer);
00315     }
00316     
00317     otab = openTable(db_name, tab_name, true);
00318     frompool_(otab);
00319     if (!otab->getDB()->isRecovering()) {
00320       if (otab->getTableID() == blob.bu_tab_id)
00321         otab->releaseReference(blob.bu_blob_id, blob.bu_blob_ref_id);
00322       else {
00323         char buffer[CS_EXC_MESSAGE_SIZE];
00324 
00325         cs_strcpy(CS_EXC_MESSAGE_SIZE, buffer, "Incorrect table ID: ");
00326         cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, blob_url);
00327         CSException::throwException(CS_CONTEXT, MS_ERR_INCORRECT_URL, buffer);
00328       }
00329     }
00330     else {
00331       char buffer[CS_EXC_MESSAGE_SIZE];
00332 
00333       cs_strcpy(CS_EXC_MESSAGE_SIZE, buffer, "Incorrect URL: ");
00334       cs_strcat(CS_EXC_MESSAGE_SIZE, buffer, blob_url);
00335       CSException::throwException(CS_CONTEXT, MS_ERR_INCORRECT_URL, buffer);
00336     }
00337     
00338     backtopool_(otab);  
00339     rtc = false;      
00340   }
00341   catch_(a);
00342   cont_(a);
00343   return rtc;
00344 }
00345 
00346 int32_t MSEngine::dereferenceBlob(const char *db_name, const char *tab_name, char *blob_url, PBMSResultPtr result)
00347 {
00348   CSThread    *self;
00349   int32_t     err = MS_OK;
00350 
00351   if ((err = enterConnectionNoThd(&self, result)))
00352     return err;
00353 
00354   inner_();
00355   if (try_dereferenceBlob(self, db_name, tab_name, blob_url))
00356     err = exceptionToResult(&self->myException, result);
00357 
00358   return_(err);
00359 }
00360 
00361 bool MSEngine::try_dropDatabase(CSThread *self, const char *db_name)
00362 {
00363   volatile bool rtc = true;
00364   try_(a) {
00365     MSDatabase::dropDatabase(db_name);
00366     rtc = false;
00367   }
00368   catch_(a);
00369   cont_(a);
00370   
00371   return rtc;
00372 }
00373 
00374 int32_t MSEngine::dropDatabase(const char *db_name, PBMSResultPtr result)
00375 {
00376   CSThread *self;
00377   int   err = MS_OK;
00378   
00379   if ((err = enterConnectionNoThd(&self, result)))
00380     return err;
00381 
00382   inner_();
00383   
00384   if (try_dropDatabase(self, db_name))
00385     err = exceptionToResult(&self->myException, result);
00386 
00387   return_(err);
00388 }
00389 
00390 //---------------
00391 typedef struct UnDoInfo {
00392   bool udo_WasRename;
00393   CSString *udo_toDatabaseName;
00394   CSString *udo_fromDatabaseName;
00395   CSString *udo_OldName;
00396   CSString *udo_NewName;
00397 } UnDoInfoRec, *UnDoInfoPtr;
00398 
00399 //---------------
00400 bool MSEngine::try_dropTable(CSThread *self, const char *db_name, const char *tab_name)
00401 {
00402   volatile bool rtc = true;
00403   try_(a) {
00404 
00405     CSPath      *new_path;
00406     CSPath      *old_path;
00407     MSOpenTable   *otab;
00408     MSOpenTablePool *tab_pool;
00409     MSTable     *tab;
00410     UnDoInfoPtr   undo_info = NULL;
00411 
00412     undo_info = (UnDoInfoPtr) cs_malloc(sizeof(UnDoInfoRec));
00413     
00414     undo_info->udo_WasRename = false;
00415     self->myInfo = undo_info;
00416 
00417     otab = openTable(db_name, tab_name, false);
00418     if (!otab) {
00419       goto end_try;
00420     }
00421     
00422     // If we are recovering do not delete the table.
00423     // It is normal for MySQL recovery scripts to delete any table they aare about to
00424     // recover and then recreate it. If this is done after the repository has been recovered
00425     // then this would delete all the recovered BLOBs in the table.
00426     if (otab->getDB()->isRecovering()) {
00427       otab->returnToPool();
00428       goto end_try;
00429     }
00430 
00431     frompool_(otab);
00432 
00433     // Before dropping the table the table ref file is renamed so that
00434     // it is out of the way incase a new table is created before the
00435     // old one is cleaned up.
00436     
00437     old_path = otab->getDBTable()->getTableFile();
00438     push_(old_path);
00439 
00440     new_path = otab->getDBTable()->getTableFile(tab_name, true);
00441 
00442     // Rearrage the object stack to pop the otab object
00443     pop_(old_path);
00444     pop_(otab);
00445 
00446     push_(new_path);
00447     push_(old_path);
00448     frompool_(otab);
00449     
00450     tab = otab->getDBTable();
00451     pop_(otab);
00452     push_(tab);
00453 
00454     tab_pool = MSTableList::lockTablePoolForDeletion(otab);
00455     frompool_(tab_pool);
00456 
00457     if (old_path->exists())
00458       old_path->move(RETAIN(new_path));
00459     tab->myDatabase->dropTable(RETAIN(tab));
00460     
00461     /* Add the table to the temp delete list if we are not recovering... */
00462     tab->prepareToDelete();
00463 
00464     backtopool_(tab_pool);  // The will unlock and close the table pool freeing all tables in it.
00465     pop_(tab);        // Returning the pool will have released this. (YUK!)
00466     release_(old_path);
00467     release_(new_path);
00468 
00469 
00470         
00471 end_try:
00472     rtc = false;  
00473   }
00474   catch_(a);
00475   cont_(a);
00476   return rtc;
00477 }
00478 
00479 //---------------
00480 int32_t MSEngine::dropTable(const char *db_name, const char *tab_name, PBMSResultPtr result)
00481 {
00482   CSThread  *self;
00483   int     err = MS_OK;
00484 
00485   if ((err = enterConnectionNoThd(&self, result)))
00486     return err;
00487 
00488   inner_();
00489   if (try_dropTable(self, db_name, tab_name))
00490     err = exceptionToResult(&self->myException, result);
00491 
00492   outer_();
00493   exitConnection();
00494   return err;
00495 }
00496 
00497 //---------------
00498 static void completeDeleteTable(UnDoInfoPtr info, bool ok)
00499 {
00500   // TO DO: figure out a way to undo the delete.
00501   cs_free(info);
00502   if (!ok) 
00503     CSException::throwException(CS_CONTEXT, MS_ERR_NOT_IMPLEMENTED, "Cannot undo delete table.");
00504 }
00505 
00506 //---------------
00507 bool MSEngine::renameTable(const char *from_db_name, const char *from_table, const char *to_db_name, const char *to_table)
00508 {
00509   MSOpenTable   *otab;
00510   CSPath      *from_path;
00511   CSPath      *to_path;
00512   MSOpenTablePool *tab_pool;
00513   MSTable     *tab;
00514 
00515   enter_();
00516   
00517   if (strcmp(to_db_name, from_db_name) != 0) {
00518     CSException::throwException(CS_CONTEXT, MS_ERR_NOT_IMPLEMENTED, "Cannot rename tables containing BLOBs across databases (yet). Sorry!");
00519   }
00520   
00521   otab = openTable(from_db_name, from_table, false);
00522   if (!otab)
00523     return_(false);
00524     
00525   frompool_(otab);
00526 
00527   if (otab->getDB()->isRecovering()) 
00528     CSException::throwException(CS_CONTEXT, MS_ERR_RECOVERY_IN_PROGRESS, "Cannot rename tables during repository recovery.");
00529 
00530   from_path = otab->getDBTable()->getTableFile();
00531   push_(from_path);
00532 
00533   to_path = otab->getDBTable()->getTableFile(to_table, false);
00534 
00535   // Rearrage the object stack to pop the otab object
00536   pop_(from_path);
00537   pop_(otab);
00538 
00539   push_(to_path);
00540   push_(from_path);
00541   frompool_(otab);
00542 
00543   otab->openForReading();
00544   tab = otab->getDBTable();
00545   tab->retain();
00546   pop_(otab);
00547   push_(tab);
00548   
00549   tab_pool = MSTableList::lockTablePoolForDeletion(otab);
00550   frompool_(tab_pool);
00551 
00552   from_path->move(RETAIN(to_path));
00553   tab->myDatabase->renameTable(tab, to_table);
00554 
00555   backtopool_(tab_pool);  // The will unlock and close the table pool freeing all tables in it.
00556   pop_(tab);        // Returning the pool will have released this. (YUK!)
00557   release_(from_path);
00558   release_(to_path);
00559   
00560   return_(true);
00561 }
00562 
00563 //---------------
00564 bool MSEngine::try_renameTable(CSThread *self, const char *from_db_name, const char *from_table, const char *to_db_name, const char *to_table)
00565 {
00566   volatile bool rtc = true;
00567   try_(a) {
00568     UnDoInfoPtr undo_info = (UnDoInfoPtr) cs_malloc(sizeof(UnDoInfoRec));
00569     push_ptr_(undo_info);
00570 
00571     undo_info->udo_WasRename = true;
00572     if (renameTable(from_db_name, from_table, to_db_name, to_table)) {    
00573       undo_info->udo_fromDatabaseName = CSString::newString(from_db_name);
00574       push_(undo_info->udo_fromDatabaseName);
00575 
00576       undo_info->udo_toDatabaseName = CSString::newString(to_db_name);
00577       push_(undo_info->udo_toDatabaseName);
00578 
00579       undo_info->udo_OldName = CSString::newString(from_table);
00580       push_(undo_info->udo_OldName);
00581 
00582       undo_info->udo_NewName = CSString::newString(to_table);
00583       
00584       pop_(undo_info->udo_OldName);
00585       pop_(undo_info->udo_toDatabaseName);
00586       pop_(undo_info->udo_fromDatabaseName);
00587     } else {
00588       undo_info->udo_fromDatabaseName = undo_info->udo_toDatabaseName = undo_info->udo_OldName = undo_info->udo_NewName = NULL;
00589     }
00590     self->myInfo = undo_info;
00591     pop_(undo_info);
00592     rtc = false;      
00593   }
00594   catch_(a);
00595   cont_(a);
00596   return rtc;
00597 }
00598 
00599 //---------------
00600 int32_t MSEngine::renameTable(const char *from_db_name, const char *from_table, const char *to_db_name, const char *to_table, PBMSResultPtr result)
00601 {
00602   CSThread  *self;
00603   int err = MS_OK;
00604 
00605   if ((err = enterConnectionNoThd(&self, result)))
00606     return err;
00607 
00608   inner_();
00609   if (try_renameTable(self, from_db_name, from_table, to_db_name, to_table))
00610     err = exceptionToResult(&self->myException, result);
00611 
00612   outer_();
00613   exitConnection();
00614   return err;
00615 }
00616 
00617 //---------------
00618 void MSEngine::completeRenameTable(UnDoInfoPtr info, bool ok)
00619 {
00620   // Swap the paths around here to revers the rename.
00621   CSString    *from_db_name= info->udo_toDatabaseName;
00622   CSString    *to_db_name= info->udo_fromDatabaseName;
00623   CSString    *from_table= info->udo_NewName;
00624   CSString    *to_table= info->udo_OldName;
00625   
00626   enter_();
00627   
00628   cs_free(info);
00629   if (from_db_name) {
00630     push_(from_db_name);
00631     push_(from_table);
00632     push_(to_db_name);
00633     push_(to_table);
00634     if (!ok) 
00635       renameTable(from_db_name->getCString(), from_table->getCString(), to_db_name->getCString(), to_table->getCString());
00636       
00637     release_(to_table);
00638     release_(to_db_name);
00639     release_(from_table);
00640     release_(from_db_name);
00641   }
00642   exit_();
00643 }
00644 
00645 //---------------
00646 static bool try_CompleteTransaction(CSThread *self, bool ok)
00647 {
00648   volatile bool rtc = true;
00649   try_(a) {
00650     if (ok)
00651       MSTransactionManager::commit();
00652     else if (self->myIsAutoCommit)
00653       MSTransactionManager::rollback();
00654     else
00655       MSTransactionManager::rollbackToPosition(self->myStartStmt); // Rollback the last logical statement.
00656     rtc = false;
00657   }
00658   catch_(a)
00659   cont_(a);
00660   
00661   return rtc;
00662 }
00663 
00664 //---------------
00665 void MSEngine::callCompleted(bool ok)
00666 {
00667   CSThread  *self;
00668   PBMSResultRec result;
00669   
00670   if (enterConnectionNoThd(&self, &result))
00671     return ;
00672 
00673   if (self->myInfo) {
00674     UnDoInfoPtr info = (UnDoInfoPtr) self->myInfo;
00675     if (info->udo_WasRename) 
00676       completeRenameTable(info, ok);
00677     else 
00678       completeDeleteTable(info, ok);
00679 
00680     
00681     self->myInfo = NULL;
00682   } else if (self->myTID && (self->myIsAutoCommit || !ok)) {
00683     inner_();
00684     if (try_CompleteTransaction(self, ok)) {
00685       self->logException();
00686     }
00687     outer_();
00688   }
00689   
00690   self->myStartStmt = self->myStmtCount;
00691 }
00692 
00693 //---------------
00694 MSOpenTable *MSEngine::openTable(const char *db_name, const char *tab_name, bool create)
00695 {
00696   MSOpenTable   *otab = NULL;
00697   uint32_t db_id, tab_id;
00698   enter_();
00699   
00700   if ( MSDatabase::convertTableAndDatabaseToIDs(db_name, tab_name, &db_id, &tab_id, create))  
00701     otab = MSTableList::getOpenTableByID(db_id, tab_id);
00702     
00703   return_(otab);
00704 }
00705 
00706 //---------------
00707 bool MSEngine::couldBeURL(const char *blob_url, size_t length)
00708 {
00709   MSBlobURLRec blob;
00710   return PBMSBlobURLTools::couldBeURL(blob_url, length, &blob);
00711 }
00712 
00713 //---------------
00714 int MSEngine::exceptionToResult(CSException *e, PBMSResultPtr result)
00715 {
00716   const char *context, *trace;
00717 
00718   result->mr_code = e->getErrorCode();
00719   cs_strcpy(MS_RESULT_MESSAGE_SIZE, result->mr_message, e->getMessage());
00720   context = e->getContext();
00721   trace = e->getStackTrace();
00722   if (context && *context) {
00723     cs_strcpy(MS_RESULT_STACK_SIZE, result->mr_stack, context);
00724     if (trace && *trace)
00725       cs_strcat(MS_RESULT_STACK_SIZE, result->mr_stack, "\n");
00726   }
00727   else
00728     *result->mr_stack = 0;
00729   if (trace && *trace)
00730     cs_strcat(MS_RESULT_STACK_SIZE, result->mr_stack, trace);
00731   return MS_ERR_ENGINE;
00732 }
00733 
00734 //---------------
00735 int MSEngine::errorResult(const char *func, const char *file, int line, int err, const char *message, PBMSResultPtr result)
00736 {
00737   CSException e;
00738     
00739   e.initException(func, file, line, err, message);
00740   return exceptionToResult(&e, result);
00741 }
00742 
00743 //---------------
00744 int MSEngine::osErrorResult(const char *func, const char *file, int line, int err, PBMSResultPtr result)
00745 {
00746   CSException e;
00747     
00748   e.initOSError(func, file, line, err);
00749   return MSEngine::exceptionToResult(&e, result);
00750 }
00751 
00752 //---------------
00753 int MSEngine::enterConnection(THD *thd, CSThread **r_self, PBMSResultPtr result, bool doCreate)
00754 {
00755   CSThread  *self = NULL;
00756 
00757 #ifndef DRIZZLED
00758   // In drizzle there is no 1:1 relationship between pthreads and sessions
00759   // so we must always get it from the session handle NOT the current pthread.
00760   self = CSThread::getSelf();
00761 #endif
00762   if (!self) {  
00763     if (thd) {
00764       if (!(self = pbms_getMySelf(thd))) {
00765         if (!doCreate)
00766           return MS_ERR_NOT_FOUND;
00767           
00768         if (!(self = CSThread::newCSThread()))
00769           return osErrorResult(CS_CONTEXT, ENOMEM, result);
00770         if (!CSThread::attach(self))
00771           return MSEngine::exceptionToResult(&self->myException, result);
00772         pbms_setMySelf(thd, self);
00773       } else {
00774         if (!CSThread::setSelf(self))
00775           return MSEngine::exceptionToResult(&self->myException, result);
00776       }
00777     } else {
00778       if (!doCreate)
00779         return MS_ERR_NOT_FOUND;
00780         
00781       if (!(self = CSThread::newCSThread()))
00782         return osErrorResult(CS_CONTEXT, ENOMEM, result);
00783       if (!CSThread::attach(self))
00784         return MSEngine::exceptionToResult(&self->myException, result);
00785     }
00786   }
00787 
00788   *r_self = self;
00789   return MS_OK;
00790 }
00791 
00792 //---------------
00793 int MSEngine::enterConnectionNoThd(CSThread **r_self, PBMSResultPtr result)
00794 {
00795   return enterConnection(current_thd, r_self, result, true);
00796 }
00797 
00798 //---------------
00799 void MSEngine::exitConnection()
00800 {
00801   THD     *thd = (THD *) current_thd;
00802   CSThread  *self;
00803 
00804   self = CSThread::getSelf();
00805   if (self && self->pbms_api_owner)
00806     return;
00807 
00808 
00809   if (thd)
00810     CSThread::setSelf(NULL);
00811   else {
00812     self = CSThread::getSelf();
00813     CSThread::detach(self);
00814   }
00815 }
00816 
00817 //---------------
00818 void MSEngine::closeConnection(THD* thd)
00819 {
00820   CSThread  *self;
00821 
00822   self = CSThread::getSelf();
00823   if (self && self->pbms_api_owner)
00824     return;
00825 
00826   if (thd) {
00827     if ((self = pbms_getMySelf(thd))) {
00828       pbms_setMySelf(thd, NULL);
00829       CSThread::setSelf(self);
00830       CSThread::detach(self);
00831     }
00832   }
00833   else {
00834     self = CSThread::getSelf();
00835     CSThread::detach(self);
00836   }
00837 }
00838 
00839 
00840 
00841