Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

MysqlDb.cc

Go to the documentation of this file.
00001 /*************************************************************************** 00002 * 00003 * $Id: MysqlDb.cc,v 1.38 2006/08/17 02:58:56 deph Exp $ 00004 * 00005 * Author: Laurent Conin 00006 *************************************************************************** 00007 * 00008 * Description: Mysql - SQL Query handler 00009 * 00010 *************************************************************************** 00011 * 00012 * $Log: MysqlDb.cc,v $ 00013 * Revision 1.38 2006/08/17 02:58:56 deph 00014 * updated load balancer - removing hard-coded nodes from API to xml 00015 * 00016 * Revision 1.37 2006/08/04 15:07:43 deph 00017 * Corrected const char / char inconsistancy with the vectors for standalone version 00018 * 00019 * Revision 1.36 2006/06/02 18:24:22 deph 00020 * removed debug output from previous checkin 00021 * 00022 * Revision 1.31 2005/12/15 03:14:27 jeromel 00023 * Mem Leak fixes / Missing delete in new and stream context. 00024 * 00025 * Revision 1.30 2004/04/28 20:28:40 deph 00026 * added protection against empty string line 245 00027 * 00028 * Revision 1.29 2004/01/15 00:02:24 fisyak 00029 * Replace ostringstream => StString, add option for alpha 00030 * 00031 * Revision 1.28 2003/09/18 00:51:59 porter 00032 * initialized mhasBinaryQuery flag 00033 * 00034 * Revision 1.27 2003/09/16 22:44:17 porter 00035 * got rid of all ostrstream objects; replaced with StString+string. 00036 * modified rules.make and added file stdb_streams.h for standalone compilation 00037 * 00038 * Revision 1.26 2003/09/02 17:57:49 perev 00039 * gcc 3.2 updates + WarnOff 00040 * 00041 * Revision 1.25 2003/07/02 18:39:23 porter 00042 * added server version to connection notification and host:port to connection failure notification 00043 * 00044 * Revision 1.24 2003/04/11 22:47:27 porter 00045 * Added a fast multi-row write model specifically needed by the daqEventTag 00046 * writer. Speed increased from about 100Hz to ~3000Hz. It is only invoked if 00047 * the table is marked as Non-Indexed (daqTags & scalers). For non-indexed tables 00048 * which include binary stored data (we don't have any yet), the fast writer has 00049 * to invoke a slower buffer so that the rates are a bit slower (~500Hz at 50 rows/insert). 00050 * 00051 * Revision 1.23 2003/02/12 22:12:45 porter 00052 * moved warning message about null columns (checked in 2 days ago) from the 00053 * depths of the mysql coding into the StDbTable code. This suppresses confusing 00054 * warnings from tables that have had elements removed but their storage columns 00055 * still exist in the database. 00056 * 00057 * Revision 1.22 2003/02/11 03:22:07 porter 00058 * added warning message individual columns return null data 00059 * 00060 * Revision 1.21 2002/04/16 19:44:49 porter 00061 * changed non-dbname in arguement of mysql_real_connect from 0 to NULL. mysql 00062 * perfers this. Updated rules.make for local mysql installation on linux 00063 * 00064 * Revision 1.20 2002/03/22 19:05:38 porter 00065 * #-of-retries on server connect increased to 7 with timeout period doubled per 00066 * retry starting at 1 sec. DOES NOT work (is ignored) on STAR's Redhat 6.2 00067 * version of mysqlclient but does on Redhat 7.2. Needed for maintainable 00068 * multiple mirror servers using dns for round-robin load balancing. 00069 * 00070 * Revision 1.19 2002/01/30 15:40:47 porter 00071 * changed limits on flavor tag & made defaults retrieving more readable 00072 * 00073 * Revision 1.18 2001/12/21 04:54:33 porter 00074 * sped up table definition for emc and changed some ostrstream usage for 00075 * insure tests 00076 * 00077 * Revision 1.17 2001/04/25 17:13:19 perev 00078 * HPcorrs 00079 * 00080 * Revision 1.16 2001/03/31 15:03:46 porter 00081 * fix bug in StDbManagerImpl::getDbName accidently introduced yesterday 00082 * & added new diagnostic message in MysqlDb 00083 * 00084 * Revision 1.15 2001/03/30 18:48:26 porter 00085 * modified code to keep Insure from wigging-out on ostrstream functions. 00086 * moved some messaging into a StDbSql method. 00087 * 00088 * Revision 1.14 2001/03/22 19:39:17 porter 00089 * make a check to avoid mysql bug on linux where selecting an 00090 * unknown database hangs the connection 00091 * 00092 * Revision 1.13 2001/02/09 23:06:24 porter 00093 * replaced ostrstream into a buffer with ostrstream creating the 00094 * buffer. The former somehow clashed on Solaris with CC5 iostream (current .dev) 00095 * 00096 * Revision 1.12 2001/01/22 18:37:49 porter 00097 * Update of code needed in next year running. This update has little 00098 * effect on the interface (only 1 method has been changed in the interface). 00099 * Code also preserves backwards compatibility so that old versions of 00100 * StDbLib can read new table structures. 00101 * -Important features: 00102 * a. more efficient low-level table structure (see StDbSql.cc) 00103 * b. more flexible indexing for new systems (see StDbElememtIndex.cc) 00104 * c. environment variable override KEYS for each database 00105 * d. StMessage support & clock-time logging diagnostics 00106 * -Cosmetic features 00107 * e. hid stl behind interfaces (see new *Impl.* files) to again allow rootcint access 00108 * f. removed codes that have been obsolete for awhile (e.g. db factories) 00109 * & renamed some classes for clarity (e.g. tableQuery became StDataBaseI 00110 * and mysqlAccessor became StDbSql) 00111 * 00112 * Revision 1.11 2000/08/15 22:51:51 porter 00113 * Added Root2DB class from Masashi Kaneta 00114 * + made code more robust against requesting data from non-existent databases 00115 * 00116 * Revision 1.10 2000/07/27 01:59:18 porter 00117 * fixed bug in delete vs delete [] 00118 * fixed up LDFLAGS for linux/g++ 00119 * 00120 * Revision 1.9 2000/06/02 13:37:36 porter 00121 * built up list of minor changes: 00122 * - made buffer more robust for certain null inputs 00123 * - fixed small leak in StDbTables & restructure call to createMemory 00124 * - added dbRhic as a database domain in StDbDefs 00125 * - added setUser() in StDbManager 00126 * - added more diagnostic printouts in mysqlAccessor.cc 00127 * 00128 * Revision 1.8 2000/03/28 17:03:18 porter 00129 * Several upgrades: 00130 * 1. configuration by timestamp for Conditions 00131 * 2. query by whereClause made more systematic 00132 * 3. conflict between db-stored comments & number lists resolved 00133 * 4. ensure endtime is correct for certain query falures 00134 * 5. dbstl.h->handles ObjectSpace & RogueWave difference (Online vs Offline) 00135 * 00136 * Revision 1.7 2000/03/01 20:56:15 porter 00137 * 3 items: 00138 * 1. activated reConnect for server timeouts 00139 * 2. activated connection sharing; better resource utilization but poorer 00140 * logging 00141 * 3. made rollback method in mysqlAccessor more robust (affects writes only) 00142 * 00143 * Revision 1.6 2000/02/18 16:58:08 porter 00144 * optimization of table-query, + whereClause gets timeStamp if indexed 00145 * + fix to write multiple rows algorithm 00146 * 00147 * Revision 1.5 2000/02/15 20:27:43 porter 00148 * Some updates to writing to the database(s) via an ensemble (should 00149 * not affect read methods & haven't in my tests. 00150 * - closeAllConnections(node) & closeConnection(table) method to mgr. 00151 * - 'NullEntry' version to write, with setStoreMode in table; 00152 * - updated both StDbTable's & StDbTableDescriptor's copy-constructor 00153 * 00154 * Revision 1.4 2000/01/27 05:54:31 porter 00155 * Updated for compiling on CC5 + HPUX-aCC + KCC (when flags are reset) 00156 * Fixed reConnect()+transaction model mismatch 00157 * added some in-code comments 00158 * 00159 * Revision 1.3 1999/12/07 21:25:25 porter 00160 * some fixes for linux warnings 00161 * 00162 * Revision 1.2 1999/09/30 02:05:59 porter 00163 * add StDbTime to better handle timestamps, modify SQL content (mysqlAccessor) 00164 * allow multiple rows (StDbTable), & Added the comment sections at top of 00165 * each header and src file 00166 * 00167 **************************************************************************/ 00168 #include "MysqlDb.h" 00169 #include "StDbManager.hh" // for now & only for getting the message service 00170 #include "stdb_streams.h" 00171 #include "StDbDefaults.hh" 00172 #include "StDbManagerImpl.hh" 00173 00174 //#include "errmsg.h" 00175 00176 #ifdef HPUX 00177 #define freeze(i) str() 00178 #endif 00179 00180 00181 #define CR_MIN_ERROR 2000 /* For easier client code */ 00182 #define CR_MAX_ERROR 2999 00183 #define CR_UNKNOWN_ERROR 2000 00184 #define CR_SOCKET_CREATE_ERROR 2001 00185 #define CR_CONNECTION_ERROR 2002 00186 #define CR_CONN_HOST_ERROR 2003 00187 #define CR_IPSOCK_ERROR 2004 00188 #define CR_UNKNOWN_HOST 2005 00189 #define CR_SERVER_GONE_ERROR 2006 00190 #define CR_VERSION_ERROR 2007 00191 #define CR_OUT_OF_MEMORY 2008 00192 #define CR_WRONG_HOST_INFO 2009 00193 #define CR_LOCALHOST_CONNECTION 2010 00194 #define CR_TCP_CONNECTION 2011 00195 #define CR_SERVER_HANDSHAKE_ERR 2012 00196 #define CR_SERVER_LOST 2013 00197 #define CR_COMMANDS_OUT_OF_SYNC 2014 00198 #define CR_NAMEDPIPE_CONNECTION 2015 00199 #define CR_NAMEDPIPEWAIT_ERROR 2016 00200 #define CR_NAMEDPIPEOPEN_ERROR 2017 00201 #define CR_NAMEDPIPESETSTATE_ERROR 2018 00202 00203 #define __CLASS__ "MysqlDb" 00204 00205 00206 static const char* binaryMessage = {"Cannot Print Query with Binary data"}; 00207 static MYSQL *conn; 00208 00209 00210 00212 00213 MysqlDb::MysqlDb(): mdbhost(0), mdbName(NULL), mdbuser(0), mdbpw(0), mdbPort(0),mdbServerVersion(0),mlogTime(false) { 00214 00215 mhasConnected=false; 00216 mhasBinaryQuery=false; 00217 mtimeout=1; 00218 mQuery=0; 00219 mQueryLast=0; 00220 mRes= new MysqlResult; 00221 for(int i=0;i<200;i++)cnames[i]=0; 00222 } 00224 00225 MysqlDb::~MysqlDb(){ 00226 if(mQuery) delete [] mQuery; 00227 if(mQueryLast) delete [] mQueryLast; 00228 Release(); 00229 if(mRes) delete mRes; 00230 if(mhasConnected)mysql_close(&mData); 00231 if(mdbhost) delete [] mdbhost; 00232 if(mdbuser) delete [] mdbuser; 00233 if(mdbpw) delete [] mdbpw; 00234 if(mdbName) delete [] mdbName; 00235 if(mdbServerVersion) delete [] mdbServerVersion; 00236 00237 } 00239 00240 vector<string>::iterator MysqlDb::RecommendedServer(vector<string>* MyServerList, char* sock, int port) 00241 { 00242 vector<string>::iterator rtrn = MyServerList->begin(); 00243 00244 std::vector<std::string>::iterator I = MyServerList->begin(); 00245 00246 unsigned long nproc_min = ULONG_MAX; 00247 while (I!=MyServerList->end()) 00248 { 00249 conn = mysql_init(0); 00250 00251 if (conn==0) 00252 { 00253 cout << "StDbManagerImpl::RecommendedServer() mysql_init(0) failed \n"; 00254 return rtrn; 00255 } 00256 00257 if (mysql_real_connect(conn,(*I).c_str(), "loadbalancer","lbdb","test",port,sock,0)==NULL) 00258 { 00259 cout << "StDbManagerImpl::RecommendedServer() mysql_real_connect "<< conn << " "<<(*I).c_str()<< 00260 " "<<port<<" "<<sock<<" failed\n"; 00261 mysql_close(conn); 00262 return rtrn; 00263 } 00264 00265 if (mysql_query(conn, "show processlist") != 0 ) 00266 { 00267 cout <<"StDbManagerImpl::RecommendedServer() show processlist failed\n"; 00268 return rtrn; 00269 } 00270 00271 MYSQL_RES *res_set = mysql_store_result(conn); 00272 unsigned long nproc = mysql_num_rows(res_set); 00273 cout <<" Server "<<(*I).c_str()<< " "<< nproc << " processes \n"; 00274 mysql_close(conn); 00275 00276 if (nproc<nproc_min) 00277 { 00278 nproc_min = nproc; 00279 rtrn = I; 00280 } 00281 ++I; 00282 } 00283 00284 return rtrn; 00285 } 00287 bool MysqlDb::reConnect(){ 00288 #define __METHOD__ "reConnect()" 00289 00290 bool connected=false; 00291 unsigned int timeOutConnect=mtimeout; 00292 while(!connected && timeOutConnect<600){ 00293 mysql_options(&mData,MYSQL_OPT_CONNECT_TIMEOUT,(const char*)&timeOutConnect); 00294 if(mysql_real_connect(&mData,mdbhost,mdbuser,mdbpw,mdbName,mdbPort,NULL,0)) 00295 connected=true; 00296 if(!connected){ 00297 timeOutConnect*=2; 00298 StString wm; 00299 wm<<" Connection Failed with MySQL on "<<mdbhost<<":"<<mdbPort<<stendl; 00300 wm<<" Returned error ="; 00301 wm<<mysql_error(&mData)<<". Will re-try with timeout set at \n==> "; 00302 wm<<timeOutConnect<<" seconds <=="; 00303 StDbManager::Instance()->printInfo((wm.str()).c_str(),dbMConnect,__LINE__,__CLASS__,__METHOD__); 00304 } 00305 } 00306 00307 if(connected){ 00308 if(mdbServerVersion) delete [] mdbServerVersion; 00309 //MPD added 4/28/04 check for valid (not Null) mData.server_version 00310 if(!mData.server_version){ 00311 StString smm; 00312 smm<<" No Server version - most likely incompatable libraries \n CONTACT ADMIN"; 00313 StDbManager::Instance()->printInfo((smm.str()).c_str(),dbMConnect,__LINE__,__CLASS__,__METHOD__); 00314 assert(mData.server_version); 00315 } 00316 //MPD end addition 00317 00318 mdbServerVersion=new char[strlen(mData.server_version)+1]; 00319 strcpy(mdbServerVersion,mData.server_version); 00320 } 00321 00322 return connected; 00323 00324 #undef __METHOD__ 00325 } 00326 00328 bool MysqlDb::Connect(const char *aHost, const char *aUser, const char *aPasswd, const char *aDb, const int aPort){ 00329 #define __METHOD__ "Connect(host,user,pw,database,port)" 00330 00331 if(mdbhost) delete [] mdbhost; 00332 mdbhost = new char[strlen(aHost)+1]; 00333 strcpy(mdbhost,aHost); 00334 00335 if(aUser){ 00336 if(mdbuser) delete [] mdbuser; 00337 mdbuser = new char[strlen(aUser)+1]; strcpy(mdbuser,aUser); 00338 } 00339 if(aPasswd){ 00340 if(mdbpw) delete [] mdbpw; 00341 mdbpw = new char[strlen(aPasswd)+1]; strcpy(mdbpw,aPasswd); 00342 } 00343 mdbPort = aPort; 00344 // cout << "aHost = "<<mdbhost<<endl; 00345 //cout << " Calling load balancer\n"; 00346 clock_t start,finish; 00347 double lbtime; 00348 start = clock(); 00349 00350 std::vector<std::string>::iterator myserver = RecommendedServer(&(my_manager->xmlServerList), NULL, mdbPort); 00351 strcpy(mdbhost,(*myserver).c_str()); 00352 00353 finish = clock(); 00354 lbtime = (double(finish)-double(start))/CLOCKS_PER_SEC*1000; 00355 cout << " Load balancer took "<<lbtime<<" ms, will use "<<mdbhost<<" \n"; 00356 00357 if(mdbName) { 00358 delete [] mdbName; 00359 mdbName=NULL; 00360 } 00361 if(aDb && (strcmp(aDb," ")!=0)){ 00362 mdbName = new char[strlen(aDb)+1]; 00363 strcpy(mdbName,aDb); 00364 } 00365 00366 bool tRetVal = false; 00367 double t0=mqueryLog.wallTime(); 00368 if(mlogTime)mconnectLog.start(); 00369 if (!mysql_init(&mData)) 00370 return (bool) StDbManager::Instance()->printInfo("Mysql Init Error=",mysql_error(&mData),dbMErr,__LINE__,__CLASS__,__METHOD__); 00371 00372 // char *connString; 00373 StString cs; 00374 if(reConnect()){ 00375 // if(mysql_real_connect(&mData,aHost,aUser,aPasswd,bDb,aPort,NULL,0)){ 00376 t0=mqueryLog.wallTime()-t0; 00377 cs<< "Server Connecting:"; if(mdbName)cs<<" DB=" << mdbName ; 00378 cs<< " Host=" << mdbhost <<":"<<aPort <<stendl; 00379 cs<< " --> Connection Time="<<t0<<" sec "; 00380 if(mdbServerVersion)cs<<" MysqlVersion="<<mdbServerVersion; 00381 00382 StDbManager::Instance()->printInfo((cs.str()).c_str(),dbMConnect,__LINE__,__CLASS__,__METHOD__); 00383 tRetVal=true; 00384 } else { 00385 cs << "Making Connection to DataBase = " << aDb; 00386 cs << " On Host = " << mdbhost <<":"<<aPort; 00387 cs << " MySQL returned error " << mysql_error(&mData); 00388 StDbManager::Instance()->printInfo((cs.str()).c_str(),dbMConnect,__LINE__,__CLASS__,__METHOD__); 00389 } 00390 00391 if(mlogTime)mconnectLog.end(); 00392 mhasConnected = tRetVal; 00393 return tRetVal; 00394 #undef __METHOD__ 00395 } 00396 00398 00399 00400 00401 char* MysqlDb::printQuery(){ return mQueryLast; }; 00402 00404 void MysqlDb::RazQuery() { 00405 00406 if (mQueryLast){ 00407 delete [] mQueryLast; 00408 mQueryLast=0; 00409 } 00410 if(mhasBinaryQuery){ 00411 mQueryLast = new char[strlen(binaryMessage)+1]; 00412 strcpy(mQueryLast,binaryMessage); 00413 if(mQuery)delete [] mQuery; 00414 } else { 00415 if(mQuery){ 00416 mQueryLast=new char[strlen(mQuery)+1]; 00417 strcpy(mQueryLast,mQuery); 00418 delete [] mQuery; 00419 } 00420 } 00421 00422 mQuery = 0;//new char[1]; 00423 mQueryLen=0; 00424 // strcpy(mQuery,""); 00425 00426 mhasBinaryQuery=false; 00427 } 00428 00429 bool MysqlDb::checkForTable(const char* tableName){ 00430 00431 mRes->Release(); 00432 mRes->mRes=mysql_list_tables(&mData,tableName); 00433 if(mRes->mRes==NULL) return false; 00434 mRes->Release(); 00435 00436 return true; 00437 }; 00438 00440 00441 bool MysqlDb::ExecQuery(){ 00442 #define __METHOD__ "ExecQuery()" 00443 00444 mqueryState=false; 00445 00446 // cout<<"MysqlDb::ExecQuery() "; 00447 // cout<<mQuery<<endl; 00448 00449 if(mlogTime)mqueryLog.start(); 00450 00451 int status=mysql_real_query(&mData,mQuery,mQueryLen); 00452 00453 if( (status!=0) && ( mysql_errno(&mData)==CR_SERVER_GONE_ERROR || mysql_errno(&mData)==CR_SERVER_LOST ) ){ 00454 StDbManager::Instance()->printInfo(mysql_error(&mData)," Lost server, will try to reconnect",dbMDebug,__LINE__,__CLASS__,__METHOD__); 00455 if(reConnect())status=mysql_real_query(&mData,mQuery,mQueryLen); 00456 } 00457 00458 if(status!=0) 00459 return StDbManager::Instance()->printInfo(" Query Failed ",mysql_error(&mData),dbMErr,__LINE__,__CLASS__,__METHOD__); 00460 00461 if(mlogTime)mqueryLog.end(); 00462 mRes->Release(); 00463 00464 if(mlogTime)msocketLog.start(); 00465 mRes->mRes=mysql_store_result(&mData); 00466 if(mlogTime)msocketLog.end(); 00467 00468 return mqueryState=true; 00469 } 00470 00472 00473 MysqlDb &MysqlDb::operator<<( const char *aQuery){ 00474 00475 if (strcmp(aQuery,";")==0){ 00476 ExecQuery(); 00477 RazQuery(); 00478 } else { 00479 00480 if(!mQuery){ 00481 mQueryLen=strlen(aQuery); 00482 mQuery = new char[mQueryLen+1]; 00483 strcpy(mQuery,aQuery); 00484 } else { 00485 char* tQuery = new char[strlen(mQuery)+1]; 00486 strcpy(tQuery,mQuery); 00487 delete [] mQuery; 00488 mQuery = new char[mQueryLen+strlen(aQuery)+1]; 00489 memcpy(mQuery,tQuery,mQueryLen); 00490 strcpy(&mQuery[mQueryLen],aQuery); 00491 delete [] tQuery; 00492 mQueryLen=mQueryLen+strlen(aQuery); 00493 } 00494 00495 } 00496 00497 return *this; 00498 } 00499 00501 00502 MysqlDb &MysqlDb::operator<<( const MysqlBin *aBin ){ 00503 00504 mhasBinaryQuery=true; 00505 00506 char *tQuery = new char[mQueryLen+aBin->mLen+1]; 00507 memcpy(tQuery,mQuery,mQueryLen); 00508 memcpy(&tQuery[mQueryLen],aBin->mBinData,aBin->mLen+1); // mBinData included null terminator 00509 // tQuery[mQueryLen+aBin->mLen]='\0'; 00510 if(mQuery)delete [] mQuery; 00511 mQuery=tQuery; 00512 mQueryLen=mQueryLen+aBin->mLen; // always not include null terminator 00513 00514 return *this; 00515 }; 00516 00518 00519 bool MysqlDb::InputStart(const char* table,StDbBuffer *aBuff, const char* colList, int nRows,bool& hasBinary){ 00520 00521 bool tRetVal=false; 00522 if(!table || !aBuff || !colList) return tRetVal; 00523 00524 bool change=aBuff->IsClientMode(); 00525 if(change) aBuff->SetStorageMode(); 00526 00527 *this << "select * from " << table << " where null"<< endsql; 00528 *this << "insert delayed into " << table << " ("<<colList<<") VALUES("; 00529 int i; 00530 00531 char* tmpString=new char[strlen(colList)+1]; 00532 strcpy(tmpString,colList); 00533 char *ptr1,*ptr2; 00534 jfields=0; 00535 bool done = false; 00536 ptr1=tmpString; 00537 00538 while(!done){ 00539 if((ptr2=strstr(ptr1,","))){ 00540 *ptr2='\0'; 00541 } else { 00542 done=true; 00543 } 00544 if(*ptr1==' ')ptr1++; 00545 if(cnames[jfields]) delete [] cnames[jfields]; 00546 cnames[jfields]=new char[strlen(ptr1)+1]; 00547 strcpy(cnames[jfields],ptr1); 00548 if(!done){ 00549 ptr1=ptr2+1; 00550 *ptr2=','; 00551 } 00552 jfields++; 00553 } 00554 delete [] tmpString; 00555 int nfields=NbFields(); 00556 int fcount=0; 00557 hasBinary=false; 00558 00559 for(int k=0;k<jfields;k++){ 00560 for(i=0;i<nfields;i++) 00561 if(strcmp(mRes->mRes->fields[i].name,cnames[k])==0)break; 00562 00563 if(i==nfields)continue; 00564 fcount++; 00565 isBlob[k]=( (IS_BLOB(mRes->mRes->fields[i].flags)) || 00566 (mRes->mRes->fields[i].type ==254) ); 00567 isBinary[k]= (mRes->mRes->fields[i].flags&BINARY_FLAG); 00568 isSpecialType[k]=(mRes->mRes->fields[i].type ==254); 00569 00570 if(isBinary[k])hasBinary=true; 00571 } 00572 if(fcount!=jfields) done=false; 00573 00574 return done; 00575 00576 }; 00577 00578 bool MysqlDb::InputRow(StDbBuffer* aBuff, int row){ 00579 00580 char* tVal;tVal=0; 00581 int len; 00582 aBuff->SetStorageMode(); 00583 if(row>0)*this<<"),("; 00584 int k; 00585 for(k=0;k<jfields;k++){ 00586 if(k!=0)*this<<","; 00587 if(isBlob[k]){ 00588 if(isBinary[k]){ 00589 if(!aBuff->ReadArray(tVal,len,cnames[k]))break; 00590 *this<<"'"<<Binary(len,(float*)tVal)<<"'"; 00591 } else if(isSpecialType[k]) { 00592 if(!aBuff->ReadScalar(tVal,cnames[k]))break; 00593 *this<<"'"<<tVal<<"'"; 00594 } else { 00595 char** tVal2=0; 00596 if(!aBuff->ReadArray(tVal2,len,cnames[k]))break; 00597 tVal=CodeStrArray(tVal2,len); 00598 for(int jj=0;jj<len;jj++)if(tVal2[jj])delete []tVal2[jj]; 00599 *this<<"'"<<tVal<<"'"; 00600 } 00601 } else { 00602 if(!aBuff->ReadScalar(tVal,cnames[k])) break; 00603 *this<<"'"<<tVal<<"'"; 00604 } 00605 } 00606 00607 aBuff->SetClientMode(); 00608 00609 if(k!=jfields){ 00610 RazQuery(); 00611 return false; 00612 } 00613 00614 return true; 00615 } 00616 00617 bool MysqlDb::InputEnd(){ 00618 00619 bool tRetVal=false; 00620 *this<<")"<<endsql; 00621 if(mqueryState)tRetVal=true; 00622 return tRetVal; 00623 00624 }; 00626 00627 bool MysqlDb::Input(const char *table,StDbBuffer *aBuff){ 00628 bool tRetVal=false; 00629 bool change=aBuff->IsClientMode(); 00630 if (change) aBuff->SetStorageMode(); 00631 aBuff->SetStorageMode(); 00632 if (aBuff) { 00633 *this << "select * from " << table << " where null"<< endsql; 00634 *this << "insert into " << table << " set "; 00635 bool tFirst=true; 00636 char* tVal;tVal=0; 00637 int len; 00638 unsigned i; 00639 00640 for (i=0;i<NbFields();i++) { 00641 if ((IS_BLOB(mRes->mRes->fields[i].flags) ) || 00642 mRes->mRes->fields[i].type ==254) { 00643 if (mRes->mRes->fields[i].flags&BINARY_FLAG) { // Binary 00644 if (aBuff->ReadArray(tVal,len,mRes->mRes->fields[i].name)){ 00645 if (tFirst) { 00646 tFirst=false; 00647 } else { 00648 *this << ","; 00649 }; 00650 *this << mRes->mRes->fields[i].name << "='" << Binary(len,(float*)tVal)<<"'"; 00651 }; 00652 }else{ // text types 00653 if(mRes->mRes->fields[i].type==254){ 00654 if (aBuff->ReadScalar(tVal,mRes->mRes->fields[i].name)) { 00655 if (tFirst) { 00656 tFirst=false; 00657 } else { 00658 *this << ","; 00659 }; 00660 *this << mRes->mRes->fields[i].name << "='" << tVal << "'"; 00661 }; 00662 } else { 00663 char** tVal2=0; 00664 if (aBuff->ReadArray(tVal2,len,mRes->mRes->fields[i].name)){ 00665 tVal=CodeStrArray(tVal2,len); 00666 int j;for (j=0;j<len;j++) {if (tVal2[j]) delete [] tVal2[j];}; 00667 delete [] tVal2; 00668 if (tFirst) { 00669 tFirst=false; 00670 } else { 00671 *this << ","; 00672 }; 00673 *this << mRes->mRes->fields[i].name << "='" << tVal<<"'"; 00674 } 00675 }; 00676 }; 00677 } else { // not binary nor text 00678 if (aBuff->ReadScalar(tVal,mRes->mRes->fields[i].name)) { 00679 if (tFirst) { 00680 tFirst=false; 00681 } else { 00682 *this << ","; 00683 }; 00684 *this << mRes->mRes->fields[i].name << "='" << tVal << "'"; 00685 }; 00686 }; 00687 if (tVal) delete [] tVal;tVal=0; 00688 }; 00689 if (tFirst) { 00690 RazQuery(); 00691 } else { 00692 *this << endsql; 00693 if(mqueryState)tRetVal=true; 00694 }; 00695 }; 00696 // if (!tRetVal) cout << "insert Failed"<< endl; 00697 if (change) aBuff->SetClientMode(); 00698 aBuff->SetClientMode(); 00699 return tRetVal; 00700 }; 00701 00703 00704 bool MysqlDb::Output(StDbBuffer *aBuff){ 00705 00706 if(mlogTime)msocketLog.start(); 00707 MYSQL_ROW tRow=mysql_fetch_row(mRes->mRes); 00708 if(!tRow) return false; 00709 unsigned long * lengths=mysql_fetch_lengths(mRes->mRes); 00710 unsigned tNbFields=NbFields(); 00711 if(mlogTime)msocketLog.end(); 00712 int i; 00713 bool tRetVal=false; 00714 bool change=aBuff->IsClientMode(); 00715 if (change) aBuff->SetStorageMode(); 00716 aBuff->SetStorageMode(); 00717 00718 for (i=0;i<(int)tNbFields;i++){ 00719 if(tRow[i]){ 00720 00721 // cout <<mRes->mRes->fields[i].name<<" = "<< tRow[i] << endl; 00722 if (IS_BLOB(mRes->mRes->fields[i].flags)) { 00723 if (mRes->mRes->fields[i].flags&BINARY_FLAG) { 00724 aBuff->WriteArray((char*)tRow[i],lengths[i],mRes->mRes->fields[i].name); 00725 }else { 00726 char** tStrPtr; 00727 int len; 00728 tStrPtr=DecodeStrArray((char*)tRow[i],len); 00729 aBuff->WriteArray(tStrPtr,len,mRes->mRes->fields[i].name); 00730 for(int k=0;k<len;k++)delete [] tStrPtr[k]; 00731 delete [] tStrPtr; 00732 00733 // something of a cludge: "," are used in "Decode.." 00734 // as array delimeters. But we also want to have 00735 // char arrays for comment structures - so write'em both 00736 // to the buffer. 00737 00738 //char commentName[1024]; 00739 StString cn; 00740 cn<<mRes->mRes->fields[i].name<<".text"; 00741 aBuff->WriteScalar((char*)tRow[i],(cn.str()).c_str()); 00742 }; 00743 } else { 00744 aBuff->WriteScalar((char*)tRow[i],mRes->mRes->fields[i].name); 00745 }; 00746 } 00747 00748 /* 00749 else { 00750 00751 StString nd; 00752 nd<<"null data returned from table = "; 00753 nd<<mRes->mRes->fields[i].table<<" column="<<mRes->mRes->fields[i].name; 00754 StDbManager::Instance()->printInfo((nd.str()).c_str(),dbMWarn,__LINE__,"MysqlDb","Output(StDbBuffer* b)"); 00755 } 00756 */ 00757 00758 tRetVal=true; 00759 }; 00760 if (change) aBuff->SetClientMode(); 00761 aBuff->SetClientMode(); 00762 return tRetVal; 00763 } 00764 00766 00767 char** MysqlDb::DecodeStrArray(char* strinput , int &aLen){ 00768 00769 if(!strinput){ // shouldn't happen - should have checked before here 00770 // cout<< "null input string from mysql " << endl; 00771 char** tmparr = new char*[1]; 00772 aLen = 1; 00773 *tmparr = new char[2]; 00774 strcpy(*tmparr,"0"); 00775 return tmparr; 00776 } 00777 00778 char* tPnt=strinput; 00779 aLen=0; 00780 while (tPnt&&aLen<100) { // 100 is a limit on # comma separated values 00781 tPnt=strpbrk( tPnt,"\\,"); 00782 if (tPnt!=0){ 00783 if (*tPnt==',') { 00784 aLen++;tPnt++; 00785 } else { //(*tPnt=='\\') 00786 tPnt++;tPnt++;}; 00787 }; 00788 }; 00789 aLen++; 00790 char** strarr=new char*[aLen]; 00791 tPnt=strinput; 00792 char* tPntNew=tPnt; 00793 char *tBuff=new char[strlen(strinput)+1]; 00794 char *tBuffInd=tBuff; 00795 int tCount=0; 00796 while (tPntNew) { 00797 tPntNew=strpbrk( tPnt,"\\,"); 00798 if ((tPntNew==0)||*tPntNew==',') { 00799 if (tPntNew==0) { 00800 strcpy(tBuffInd,tPnt); 00801 00802 } else { 00803 strncpy(tBuffInd,tPnt,tPntNew-tPnt); 00804 *(tBuffInd+(tPntNew-tPnt))='\0'; 00805 } 00806 strarr[tCount]=new char[strlen(tBuff)+1]; 00807 strcpy(strarr[tCount],tBuff); 00808 tBuffInd=tBuff; 00809 tPnt=tPntNew+1; 00810 tCount++; 00811 } else { //(*tPntNew=='\\') 00812 strncpy(tBuffInd,tPnt,tPntNew-tPnt); 00813 tBuffInd=tBuffInd+(tPntNew-tPnt); 00814 tPntNew++; 00815 if(*tPntNew=='\\'||*tPntNew==',') { 00816 *tBuffInd=*tPntNew; 00817 tBuffInd++; 00818 }; 00819 *(tBuffInd)='\0'; 00820 tPnt=tPntNew+1; 00821 }; 00822 }; 00823 delete [] tBuff; 00824 return strarr; 00825 } 00826 00828 00829 char* MysqlDb::CodeStrArray(char** strarr , int aLen){ 00830 int tMaxLen=0; 00831 int i; 00832 for (i=0;i<aLen;i++) { 00833 if (strarr[i]) tMaxLen=tMaxLen+strlen(strarr[i])*2; 00834 tMaxLen++; 00835 }; 00836 char* tTempVal=new char[tMaxLen+1]; 00837 char* tRead; 00838 char* tWrite=tTempVal; 00839 for (i=0;i<aLen;i++) { 00840 if (strarr[i]){ 00841 int j; 00842 tRead=strarr[i]; 00843 for (j=0;j<(int)strlen(strarr[i]);j++) { 00844 if (*tRead=='\\'||*tRead==',') { 00845 *tWrite='\\'; 00846 tWrite++; 00847 }; 00848 *tWrite=*tRead; 00849 tWrite++; 00850 tRead++; 00851 }; 00852 }; 00853 *tWrite=','; 00854 tWrite++; 00855 }; 00856 tWrite--; 00857 *tWrite='\0'; 00858 char *tRetVal=new char[strlen(tTempVal)+1]; 00859 strcpy(tRetVal,tTempVal); 00860 if (tTempVal) delete [] tTempVal; 00861 return tRetVal; 00862 }; 00863 00865 00866 bool 00867 MysqlDb::setDefaultDb(const char* dbName){ 00868 00869 if(!dbName || strlen(dbName)==0)return false; 00870 if(mdbName) delete [] mdbName; 00871 mdbName=new char[strlen(dbName)+1]; 00872 strcpy(mdbName,dbName); 00873 if(strcmp(dbName," ")==0)return true; 00874 00875 bool tOk=false; 00876 unsigned int mysqlError; 00877 00878 if(mysql_select_db(&mData,dbName)){ 00879 00880 mysqlError = mysql_errno(&mData); 00881 if(mysqlError==CR_SERVER_GONE_ERROR || mysqlError==CR_SERVER_LOST){ 00882 reConnect(); 00883 if(mysql_select_db(&mData,dbName)){ 00884 cerr<< "Error selecting database=" << dbName << endl; 00885 tOk=false; 00886 } else { 00887 tOk=true; 00888 } 00889 } else { 00890 cerr<< "Error selecting database=" << dbName << endl; 00891 tOk=false; 00892 } 00893 } else { 00894 tOk=true; 00895 } 00896 00897 return tOk; 00898 } 00899 00901 00902 const MysqlBin *Binary(const unsigned long int aLen,const float *aBin){ 00903 static MysqlBin *tBin=0; 00904 static char *tString=0; 00905 unsigned long int tNewLen; 00906 00907 if (!tBin) tBin=new MysqlBin; 00908 if (tString) delete [] tString; 00909 00910 tString = new char[2*aLen+1]; 00911 tNewLen = mysql_escape_string(tString,(char*) aBin,aLen); 00912 tBin->Input(tNewLen,tString); 00913 return tBin; 00914 } 00915 00916 #undef __CLASS__ 00917 00918

Generated on Thu Aug 24 14:45:25 2006 for Doxygen by doxygen 1.3.7