StRoot  1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
MysqlDb.cc
1 /***************************************************************************
2  *
3  * $Id: MysqlDb.cc,v 1.72 2017/01/04 19:10:09 dmitry Exp $
4  *
5  * Author: Laurent Conin
6  ***************************************************************************
7  *
8  * Description: Mysql - SQL Query handler
9  *
10  ***************************************************************************
11  *
12  * $Log: MysqlDb.cc,v $
13  * Revision 1.72 2017/01/04 19:10:09 dmitry
14  * New compiler does not allow me do delete non-modifiable string via pointer. That is unfair! :)
15  *
16  * Revision 1.71 2015/07/10 18:58:57 dmitry
17  * fixing warning - MYSQL_RES pointer is not supposed to be deleted by client in destructor
18  *
19  * Revision 1.70 2015/05/21 20:01:15 dmitry
20  * fixed false positive aka uninitialized use of memory
21  *
22  * Revision 1.69 2015/05/15 19:56:09 dmitry
23  * more cleanup
24  *
25  * Revision 1.68 2015/05/15 19:47:16 dmitry
26  * proper delete added before overwrite
27  *
28  * Revision 1.67 2015/05/15 18:55:02 dmitry
29  * redundant pointer check removed
30  *
31  * Revision 1.66 2014/06/10 14:52:12 dmitry
32  * Jeff L. spotted INSERT DELAYED in our API (thanks!), and I removed DELAYED keyword
33  *
34  * Revision 1.65 2013/11/15 17:46:38 dmitry
35  * do not try to free memory which we don\'t own..
36  *
37  * Revision 1.64 2013/11/14 21:25:47 dmitry
38  * override for the mysql user autodetect functionality
39  *
40  * Revision 1.63 2013/05/23 19:27:08 dmitry
41  * simple hook to use database with login/pass when really needed
42  *
43  * Revision 1.62 2012/12/12 21:58:37 fisyak
44  * Add check for HAVE_CLOCK_GETTIME flag and for APPLE
45  *
46  * Revision 1.61 2012/05/04 17:19:14 dmitry
47  * Part One integration for Hyper Cache. HyperCache added to workflow, but config is set to DISABLE
48  *
49  * Revision 1.60 2011/04/04 15:44:24 dmitry
50  * fix to blacklist Calibrations_bla only
51  *
52  * Revision 1.59 2011/03/19 01:21:49 dmitry
53  * connect error messages converted to more user-frienly format
54  *
55  * Revision 1.58 2011/02/24 03:54:35 dmitry
56  * commented out unused variable
57  *
58  * Revision 1.57 2011/01/07 18:19:02 dmitry
59  * user name lookup is done once now (for speedup, based on profiler report)
60  *
61  * Revision 1.56 2011/01/07 17:12:29 dmitry
62  * fixed pseudo-leaks in c-string and xml-string assignments
63  *
64  * Revision 1.55 2010/11/19 14:54:30 dmitry
65  * added define guard (mysql version) to enable automatic reconnect in mysql 5.0.44+, excluding mysql 4
66  *
67  * Revision 1.54 2010/11/18 20:34:01 dmitry
68  * enabled automatic reconnect via mysql option
69  *
70  * Revision 1.53 2010/02/17 23:39:26 dmitry
71  * indirect log info added
72  *
73  * Revision 1.52 2009/11/23 14:36:24 dmitry
74  * tiny fix: LB will now obey Logger commands
75  *
76  * Revision 1.51 2009/11/17 17:14:52 dmitry
77  * enabled SSL + compression, if server supports it
78  *
79  * Revision 1.50 2009/09/15 21:49:06 dmitry
80  * LB timer fix, now it is accurate up to 1 ms, as planned
81  *
82  * Revision 1.49 2009/08/25 17:41:36 fine
83  * fix the compilation issues under SL5_64_bits gcc 4.3.2
84  *
85  * Revision 1.48 2009/01/26 18:55:45 genevb
86  * Fixed reporting of port numbers to what is actually used
87  *
88  * Revision 1.47 2007/10/29 22:50:55 deph
89  * Abstracted load balancer call from connect to own function called from reconnect
90  * removed extraneuos methods from header
91  *
92  * Revision 1.46 2007/09/25 15:59:53 deph
93  * Fixed fallback from LoadBalancer (PDSF problem with missing Config File)
94  *
95  * Revision 1.45 2007/08/29 21:08:13 deph
96  * Separated out string copy for load lbalancer (host name too long for legacy code) deafual
97  *
98  * Revision 1.44 2007/08/20 18:21:28 deph
99  * New Version of Load Balancer
100  *
101  * Revision 1.43 2007/08/03 18:46:30 deph
102  * Increased the number of allowed elements in a comma delimeted text field from 100 to 1024 to allow for the 768 ssd strips
103  *
104  * Revision 1.42 2007/05/16 22:48:09 deph
105  * Replaced cerr with LOG_ERROR <<endm; for logger
106  *
107  * Revision 1.41 2007/03/08 22:08:41 deph
108  * Load Balancer adjustments for machinePower features
109  *
110  * Revision 1.40 2007/01/09 16:27:39 deph
111  * Updates for load balancing "added 1)write privilege 2)xml comments 3)camelCase notation
112  *
113  * Revision 1.39 2006/11/16 21:50:40 deph
114  * additional files needed for db load balancing
115  *
116  * Revision 1.38 2006/08/17 02:58:56 deph
117  * updated load balancer - removing hard-coded nodes from API to xml
118  *
119  * Revision 1.37 2006/08/04 15:07:43 deph
120  * Corrected const char / char inconsistancy with the vectors for standalone version
121  *
122  * Revision 1.36 2006/06/02 18:24:22 deph
123  * removed debug output from previous checkin
124  *
125  * Revision 1.31 2005/12/15 03:14:27 jeromel
126  * Mem Leak fixes / Missing delete in new and stream context.
127  *
128  * Revision 1.30 2004/04/28 20:28:40 deph
129  * added protection against empty string line 245
130  *
131  * Revision 1.29 2004/01/15 00:02:24 fisyak
132  * Replace ostringstream => StString, add option for alpha
133  *
134  * Revision 1.28 2003/09/18 00:51:59 porter
135  * initialized mhasBinaryQuery flag
136  *
137  * Revision 1.27 2003/09/16 22:44:17 porter
138  * got rid of all ostrstream objects; replaced with StString+string.
139  * modified rules.make and added file stdb_streams.h for standalone compilation
140  *
141  * Revision 1.26 2003/09/02 17:57:49 perev
142  * gcc 3.2 updates + WarnOff
143  *
144  * Revision 1.25 2003/07/02 18:39:23 porter
145  * added server version to connection notification and host:port to connection failure notification
146  *
147  * Revision 1.24 2003/04/11 22:47:27 porter
148  * Added a fast multi-row write model specifically needed by the daqEventTag
149  * writer. Speed increased from about 100Hz to ~3000Hz. It is only invoked if
150  * the table is marked as Non-Indexed (daqTags & scalers). For non-indexed tables
151  * which include binary stored data (we don't have any yet), the fast writer has
152  * to invoke a slower buffer so that the rates are a bit slower (~500Hz at 50 rows/insert).
153  *
154  * Revision 1.23 2003/02/12 22:12:45 porter
155  * moved warning message about null columns (checked in 2 days ago) from the
156  * depths of the mysql coding into the StDbTable code. This suppresses confusing
157  * warnings from tables that have had elements removed but their storage columns
158  * still exist in the database.
159  *
160  * Revision 1.22 2003/02/11 03:22:07 porter
161  * added warning message individual columns return null data
162  *
163  * Revision 1.21 2002/04/16 19:44:49 porter
164  * changed non-dbname in arguement of mysql_real_connect from 0 to NULL. mysql
165  * perfers this. Updated rules.make for local mysql installation on linux
166  *
167  * Revision 1.20 2002/03/22 19:05:38 porter
168  * #-of-retries on server connect increased to 7 with timeout period doubled per
169  * retry starting at 1 sec. DOES NOT work (is ignored) on STAR's Redhat 6.2
170  * version of mysqlclient but does on Redhat 7.2. Needed for maintainable
171  * multiple mirror servers using dns for round-robin load balancing.
172  *
173  * Revision 1.19 2002/01/30 15:40:47 porter
174  * changed limits on flavor tag & made defaults retrieving more readable
175  *
176  * Revision 1.18 2001/12/21 04:54:33 porter
177  * sped up table definition for emc and changed some ostrstream usage for
178  * insure tests
179  *
180  * Revision 1.17 2001/04/25 17:13:19 perev
181  * HPcorrs
182  *
183  * Revision 1.16 2001/03/31 15:03:46 porter
184  * fix bug in StDbManagerImpl::getDbName accidently introduced yesterday
185  * & added new diagnostic message in MysqlDb
186  *
187  * Revision 1.15 2001/03/30 18:48:26 porter
188  * modified code to keep Insure from wigging-out on ostrstream functions.
189  * moved some messaging into a StDbSql method.
190  *
191  * Revision 1.14 2001/03/22 19:39:17 porter
192  * make a check to avoid mysql bug on linux where selecting an
193  * unknown database hangs the connection
194  *
195  * Revision 1.13 2001/02/09 23:06:24 porter
196  * replaced ostrstream into a buffer with ostrstream creating the
197  * buffer. The former somehow clashed on Solaris with CC5 iostream (current .dev)
198  *
199  * Revision 1.12 2001/01/22 18:37:49 porter
200  * Update of code needed in next year running. This update has little
201  * effect on the interface (only 1 method has been changed in the interface).
202  * Code also preserves backwards compatibility so that old versions of
203  * StDbLib can read new table structures.
204  * -Important features:
205  * a. more efficient low-level table structure (see StDbSql.cc)
206  * b. more flexible indexing for new systems (see StDbElememtIndex.cc)
207  * c. environment variable override KEYS for each database
208  * d. StMessage support & clock-time logging diagnostics
209  * -Cosmetic features
210  * e. hid stl behind interfaces (see new *Impl.* files) to again allow rootcint access
211  * f. removed codes that have been obsolete for awhile (e.g. db factories)
212  * & renamed some classes for clarity (e.g. tableQuery became StDataBaseI
213  * and mysqlAccessor became StDbSql)
214  *
215  * Revision 1.11 2000/08/15 22:51:51 porter
216  * Added Root2DB class from Masashi Kaneta
217  * + made code more robust against requesting data from non-existent databases
218  *
219  * Revision 1.10 2000/07/27 01:59:18 porter
220  * fixed bug in delete vs delete []
221  * fixed up LDFLAGS for linux/g++
222  *
223  * Revision 1.9 2000/06/02 13:37:36 porter
224  * built up list of minor changes:
225  * - made buffer more robust for certain null inputs
226  * - fixed small leak in StDbTables & restructure call to createMemory
227  * - added dbRhic as a database domain in StDbDefs
228  * - added setUser() in StDbManager
229  * - added more diagnostic printouts in mysqlAccessor.cc
230  *
231  * Revision 1.8 2000/03/28 17:03:18 porter
232  * Several upgrades:
233  * 1. configuration by timestamp for Conditions
234  * 2. query by whereClause made more systematic
235  * 3. conflict between db-stored comments & number lists resolved
236  * 4. ensure endtime is correct for certain query falures
237  * 5. dbstl.h->handles ObjectSpace & RogueWave difference (Online vs Offline)
238  *
239  * Revision 1.7 2000/03/01 20:56:15 porter
240  * 3 items:
241  * 1. activated reConnect for server timeouts
242  * 2. activated connection sharing; better resource utilization but poorer
243  * logging
244  * 3. made rollback method in mysqlAccessor more robust (affects writes only)
245  *
246  * Revision 1.6 2000/02/18 16:58:08 porter
247  * optimization of table-query, + whereClause gets timeStamp if indexed
248  * + fix to write multiple rows algorithm
249  *
250  * Revision 1.5 2000/02/15 20:27:43 porter
251  * Some updates to writing to the database(s) via an ensemble (should
252  * not affect read methods & haven't in my tests.
253  * - closeAllConnections(node) & closeConnection(table) method to mgr.
254  * - 'NullEntry' version to write, with setStoreMode in table;
255  * - updated both StDbTable's & StDbTableDescriptor's copy-constructor
256  *
257  * Revision 1.4 2000/01/27 05:54:31 porter
258  * Updated for compiling on CC5 + HPUX-aCC + KCC (when flags are reset)
259  * Fixed reConnect()+transaction model mismatch
260  * added some in-code comments
261  *
262  * Revision 1.3 1999/12/07 21:25:25 porter
263  * some fixes for linux warnings
264  *
265  * Revision 1.2 1999/09/30 02:05:59 porter
266  * add StDbTime to better handle timestamps, modify SQL content (mysqlAccessor)
267  * allow multiple rows (StDbTable), & Added the comment sections at top of
268  * each header and src file
269  *
270  **************************************************************************/
271 #include <assert.h>
272 #include "MysqlDb.h"
273 #include "StDbManager.hh" // for now & only for getting the message service
274 #include "stdb_streams.h"
275 #include "StDbDefaults.hh"
276 #include "StDbManagerImpl.hh"
277 
278 #include <unistd.h>
279 #include <sys/types.h>
280 #include <pwd.h>
281 #include <string>
282 
283 #include <cassert>
284 #include <ctime>
285 
286 #ifndef __STDB_STANDALONE__
287 #include "StMessMgr.h"
288 #else
289 #define LOG_DEBUG cout
290 #define LOG_INFO cout
291 #define LOG_WARN cout
292 #define LOG_ERROR cerr
293 #define LOG_FATAL cerr
294 #define LOG_QA cout
295 #define endm "\n"
296 #endif
297 
298 //#include "errmsg.h"
299 
300 #ifdef HPUX
301 #define freeze(i) str()
302 #endif
303 
304 
305 #define CR_MIN_ERROR 2000 /* For easier client code */
306 #define CR_MAX_ERROR 2999
307 #define CR_UNKNOWN_ERROR 2000
308 #define CR_SOCKET_CREATE_ERROR 2001
309 #define CR_CONNECTION_ERROR 2002
310 #define CR_CONN_HOST_ERROR 2003
311 #define CR_IPSOCK_ERROR 2004
312 #define CR_UNKNOWN_HOST 2005
313 #define CR_SERVER_GONE_ERROR 2006
314 #define CR_VERSION_ERROR 2007
315 #define CR_OUT_OF_MEMORY 2008
316 #define CR_WRONG_HOST_INFO 2009
317 #define CR_LOCALHOST_CONNECTION 2010
318 #define CR_TCP_CONNECTION 2011
319 #define CR_SERVER_HANDSHAKE_ERR 2012
320 #define CR_SERVER_LOST 2013
321 #define CR_COMMANDS_OUT_OF_SYNC 2014
322 #define CR_NAMEDPIPE_CONNECTION 2015
323 #define CR_NAMEDPIPEWAIT_ERROR 2016
324 #define CR_NAMEDPIPEOPEN_ERROR 2017
325 #define CR_NAMEDPIPESETSTATE_ERROR 2018
326 
327 #define __CLASS__ "MysqlDb"
328 
329 namespace {
330 
331 time_t get_time_nanosec() {
332 #ifdef HAVE_CLOCK_GETTIME
333  timespec ts;
334  clock_gettime(CLOCK_MONOTONIC, &ts);
335  return (ts.tv_sec*1000 + ts.tv_nsec/1000000);
336 #else
337  return 0;
338 #endif
339 }
340 
341 }
342 
343 static const char* binaryMessage = {"Cannot Print Query with Binary data"};
344 //static MYSQL *conn;
345 
346 
347 
349 
350 MysqlDb::MysqlDb(): mdbhost(0), mdbName(NULL), mdbuser(0), mdbpw(0), mdbPort(0),mdbServerVersion(0),mlogTime(false) {
351 
352  if (mdbuser == NULL && getenv("USE_LB_LOGIN") != NULL) {
353  mdbuser = (char*)"loadbalancer";
354  mdbpw = (char*)"lbdb";
355  }
356 
357 mhasConnected=false;
358 mhasBinaryQuery=false;
359 mtimeout=1;
360 mQuery=0;
361 mQueryLast=0;
362 mRes= new MysqlResult;
363  for(int i=0;i<200;i++)cnames[i]=0;
364 
365  mSysusername = "N/A";
366  struct passwd *pwd = 0;
367  pwd = getpwuid(geteuid());
368  if (pwd) {
369  mSysusername = pwd->pw_name;
370  mdbuser = (char*)mSysusername.c_str();
371  std::cout << "DB OVERRIDE default user with: " << mdbuser << std::endl;
372  } else {
373  std::cout << "DB OVERRIDE failure, user ID cannot be retrieved" << std::endl;
374  }
375 }
377 
378 MysqlDb::~MysqlDb(){
379 if(mQuery) delete [] mQuery;
380 if(mQueryLast) delete [] mQueryLast;
381 Release();
382 //if(mRes) delete mRes;
383 if(mhasConnected)mysql_close(&mData);
384 
385 //if(mdbhost) delete [] mdbhost; // no guarantee that we own this data, really
386 //if(mdbuser) delete [] mdbuser; // thus do not destroy..
387 //if(mdbpw) delete [] mdbpw;
388 //if(mdbName) delete [] mdbName;
389 // if(mdbServerVersion) delete [] mdbServerVersion;
390 
391 #ifdef MYSQL_VERSION_ID
392 # if MYSQL_VERSION_ID > 50044
393 mysql_library_end();
394 # endif
395 #endif
396 
397 }
399 bool MysqlDb::reConnect(){
400 #define __METHOD__ "reConnect()"
401 
402  bool connected=false;
403  unsigned int timeOutConnect=mtimeout;
404  my_bool auto_reconnect = 1;
405 
406  while(!connected && timeOutConnect<600){
407  mysql_options(&mData,MYSQL_OPT_CONNECT_TIMEOUT,(const char*)&timeOutConnect);
408 
409 #ifdef MYSQL_VERSION_ID
410 # if MYSQL_VERSION_ID > 50044
411  mysql_options(&mData,MYSQL_OPT_RECONNECT, &auto_reconnect);
412 # endif
413 #endif
414 
415  loadBalance(); // does nothing in the fall-back scenario
416 
417  // always returns 0, no way to check for SSL validity
418  // "AES-128-SHA" = less CPU-intensive than AES-256
419 #ifndef __APPLE__
420  mysql_ssl_set(&mData, NULL, NULL, NULL, NULL, "AES128-SHA");
421 #endif
422  unsigned long client_flag = CLIENT_COMPRESS;
423 
424 
425  if(mysql_real_connect(&mData,mdbhost,mdbuser,mdbpw,mdbName,mdbPort,NULL,client_flag)) {
426  connected=true;
427  std::string query = "SHOW STATUS LIKE 'Ssl_cipher'";
428  mysql_query(&mData, query.c_str());
429  MYSQL_RES *result = 0;
430  MYSQL_ROW row = 0;
431  int num_fields = 0;
432  result = mysql_store_result(&mData);
433  num_fields = mysql_num_fields(result);
434  if (num_fields >= 2) {
435  row = mysql_fetch_row(result);
436  if (row && row[0] && row[1]) {
437  LOG_INFO << row[0] << " = " << row[1] << endm;
438  }
439  }
440  mysql_free_result(result);
441  }
442 
443  if(!connected){
444  timeOutConnect*=2;
445  StString wm;
446  wm << " Cannot connect to " << mdbhost << ":" << mdbPort << ", database server is busy or unreachable.\n";
447  wm << " Returned error =";
448  wm << mysql_error(&mData)<<".\n Will re-try with timeout set at \n==> ";
449  wm << timeOutConnect<<" seconds <==";
450  StDbManager::Instance()->printInfo((wm.str()).c_str(),dbMConnect,__LINE__,__CLASS__,__METHOD__);
451  }
452  }
453 
454  if(connected){
455  if(mdbServerVersion) delete [] mdbServerVersion;
456  //MPD added 4/28/04 check for valid (not Null) mData.server_version
457  if(!mData.server_version){
458  StString smm;
459  smm<<" No Server version - most likely incompatible libraries \n CONTACT DATABASE ADMINISTRATOR";
460  StDbManager::Instance()->printInfo((smm.str()).c_str(),dbMConnect,__LINE__,__CLASS__,__METHOD__);
461  assert(mData.server_version);
462  }
463  //MPD end addition
464 
465  mdbServerVersion=new char[strlen(mData.server_version)+1];
466  strcpy(mdbServerVersion,mData.server_version);
467  }
468 
469  return connected;
470 
471 #undef __METHOD__
472 }
473 
475 bool MysqlDb::Connect(const char *aHost, const char *aUser, const char *aPasswd, const char *aDb, const int aPort){
476 #define __METHOD__ "Connect(host,user,pw,database,port)"
477 
478  m_Mgr.init();
479 
480  if(aUser){
481  mdbuser = new char[strlen(aUser)+1]; strcpy(mdbuser,aUser);
482  }
483  if(aPasswd){
484  if(mdbpw) delete [] mdbpw;
485  mdbpw = new char[strlen(aPasswd)+1]; strcpy(mdbpw,aPasswd);
486  }
487  mdbPort = aPort;
488  // cout << "aHost = "<<mdbhost<<endl;
489  //cout << " Calling load balancer\n";
490 
491 #ifndef NoXmlTreeReader
492  if (!my_manager->myServiceBroker)
493 #endif
494  {
495  // a fall-back scenario (NoXmlTreeReader) or lack of myServiceBroker (broken env.)
496  if(mdbhost) delete [] mdbhost;
497  mdbhost = new char[strlen(aHost)+1];
498  strcpy(mdbhost,aHost);
499  }
500 
501 
502  if(mdbName) {
503  delete [] mdbName;
504  mdbName=NULL;
505  }
506  if(aDb && (strcmp(aDb," ")!=0)){
507  mdbName = new char[strlen(aDb)+1];
508  strcpy(mdbName,aDb);
509  }
510 
511  bool tRetVal = false;
512  double t0=mqueryLog.wallTime();
513  if(mlogTime)mconnectLog.start();
514  if (!mysql_init(&mData))
515  return (bool) StDbManager::Instance()->printInfo("Mysql Init Error=",mysql_error(&mData),dbMErr,__LINE__,__CLASS__,__METHOD__);
516 
517  // char *connString;
518  StString cs;
519  if(reConnect()){
520  // if(mysql_real_connect(&mData,aHost,aUser,aPasswd,bDb,aPort,NULL,0)){
521  t0=mqueryLog.wallTime()-t0;
522  cs<< "Server Connecting:"; if(mdbName)cs<<" DB=" << mdbName ;
523  cs<< " Host=" << mdbhost <<":"<<mdbPort <<stendl;
524  cs<< " --> Connection Time="<<t0<<" sec ";
525  if(mdbServerVersion)cs<<" MysqlVersion="<<mdbServerVersion;
526 
527  StDbManager::Instance()->printInfo((cs.str()).c_str(),dbMConnect,__LINE__,__CLASS__,__METHOD__);
528  tRetVal=true;
529  } else {
530  cs << "Making Connection to DataBase = " << aDb;
531  cs << " On Host = " << mdbhost <<":"<<mdbPort;
532  cs << " MySQL returned error " << mysql_error(&mData);
533  StDbManager::Instance()->printInfo((cs.str()).c_str(),dbMConnect,__LINE__,__CLASS__,__METHOD__);
534  }
535 
536  if(mlogTime)mconnectLog.end();
537  mhasConnected = tRetVal;
538  return tRetVal;
539 #undef __METHOD__
540 }
541 
543 
544 bool MysqlDb::loadBalance()
545 {
546  bool ok = false;
547 
548 #ifndef NoXmlTreeReader
549  time_t startTime = get_time_nanosec();
550  time_t stopTime = 0, totalTime = 0;
551 
552  if (my_manager->myServiceBroker)
553  {
554  my_manager->myServiceBroker->DoLoadBalancing();
555  short mSBStatus = my_manager->myServiceBroker->GetStatus();
556  if (mSBStatus==st_db_service_broker::NO_ERROR)
557  {
558 
559  const char* lbHostName = (my_manager->myServiceBroker->GiveHostName()).c_str();
560  if(mdbhost) delete [] mdbhost;
561  mdbhost = new char[strlen(lbHostName)+1];
562  strcpy(mdbhost,lbHostName);
563  ok = true;
564  mdbPort = my_manager->myServiceBroker->GiveHostPort();
565  }
566  else
567  {
568  LOG_ERROR << "MysqlDb::Connect: StDbServiceBroker error "<<mSBStatus<<endm;
569  }
570  }
571 
572  stopTime = get_time_nanosec();
573  totalTime = stopTime - startTime;
574  LOG_INFO << "MysqlDb::Connect: Load balancer took "<< totalTime <<" ms, will use "<< mdbhost << ":" << mdbPort << endm;
575 
576 #endif
577 
578  return ok;
579 }
581 
582 
583 
584 char* MysqlDb::printQuery(){ return mQueryLast; };
585 
587 void MysqlDb::RazQuery() {
588 
589  if (mQueryLast){
590  delete [] mQueryLast;
591  mQueryLast=0;
592  }
593  if(mhasBinaryQuery){
594  mQueryLast = new char[strlen(binaryMessage)+1];
595  strcpy(mQueryLast,binaryMessage);
596  if(mQuery)delete [] mQuery;
597  } else {
598  if(mQuery){
599  mQueryLast=new char[strlen(mQuery)+1];
600  strcpy(mQueryLast,mQuery);
601  delete [] mQuery;
602  }
603  }
604 
605  mQuery = 0;//new char[1];
606  mQueryLen=0;
607  // strcpy(mQuery,"");
608 
609  mhasBinaryQuery=false;
610 }
611 
612 bool MysqlDb::checkForTable(const char* tableName){
613 
614  mRes->Release();
615  mRes->mRes=mysql_list_tables(&mData,tableName);
616  if(mRes->mRes==NULL) return false;
617  mRes->Release();
618 
619 return true;
620 };
621 
623 
624 bool MysqlDb::ExecQuery(){
625 #define __METHOD__ "ExecQuery()"
626 
627 
628  std::string mQ(mQuery,mQueryLen);
629  mQ.append(" /* RUSR: "); // real user name
630  mQ.append(mSysusername);
631  mQ.append(" | SUSR: "); // set user name
632  if (mdbuser) {
633  mQ.append(mdbuser);
634  } else {
635  mQ.append("N/A");
636  }
637  mQ.append(" */");
638 
639 mqueryState=false;
640 
641  size_t cache_length = 0;
642  if (m_Mgr.isActive()) {
643  std::string dbName = mdbName ? mdbName : "";
644  const char* res = m_Mgr.get(dbName, mQuery, cache_length);
645  if (res && cache_length) {
646  return mqueryState = true;
647  }
648  }
649 
650 if(mlogTime)mqueryLog.start();
651 
652 
653 //int status=mysql_real_query(&mData,mQuery,mQueryLen);
654  int status=mysql_real_query(&mData,mQ.c_str(), mQ.size());
655 
656  if( (status!=0) && ( mysql_errno(&mData)==CR_SERVER_GONE_ERROR || mysql_errno(&mData)==CR_SERVER_LOST ) ){
657  StDbManager::Instance()->printInfo(mysql_error(&mData)," Lost server, will try to reconnect",dbMDebug,__LINE__,__CLASS__,__METHOD__);
658  if(reConnect())status=mysql_real_query(&mData,mQuery,mQueryLen);
659  }
660 
661  if(status!=0)
662  return StDbManager::Instance()->printInfo(" Query Failed ",mysql_error(&mData),dbMErr,__LINE__,__CLASS__,__METHOD__);
663 
664  if(mlogTime)mqueryLog.end();
665  mRes->Release();
666 
667  if(mlogTime)msocketLog.start();
668  mRes->mRes=mysql_store_result(&mData);
669  if(mlogTime)msocketLog.end();
670 
671  return mqueryState=true;
672 }
673 
675 
676 MysqlDb &MysqlDb::operator<<( const char *aQuery){
677 
678  if (strcmp(aQuery,";")==0){
679  ExecQuery();
680  RazQuery();
681  } else {
682 
683  if(!mQuery){
684  mQueryLen=strlen(aQuery);
685  mQuery = new char[mQueryLen+1];
686  strcpy(mQuery,aQuery);
687  } else {
688  char* tQuery = new char[strlen(mQuery)+1];
689  strcpy(tQuery,mQuery);
690  delete [] mQuery;
691  mQuery = new char[mQueryLen+strlen(aQuery)+1];
692  memcpy(mQuery,tQuery,mQueryLen);
693  strcpy(&mQuery[mQueryLen],aQuery);
694  delete [] tQuery;
695  mQueryLen=mQueryLen+strlen(aQuery);
696  }
697 
698  }
699 
700  return *this;
701 }
702 
704 
705 MysqlDb &MysqlDb::operator<<( const MysqlBin *aBin ){
706 
707  mhasBinaryQuery=true;
708 
709  char *tQuery = new char[mQueryLen+aBin->mLen+1];
710  memcpy(tQuery,mQuery,mQueryLen);
711  memcpy(&tQuery[mQueryLen],aBin->mBinData,aBin->mLen+1); // mBinData included null terminator
712  // tQuery[mQueryLen+aBin->mLen]='\0';
713  if(mQuery)delete [] mQuery;
714  mQuery=tQuery;
715  mQueryLen=mQueryLen+aBin->mLen; // always not include null terminator
716 
717  return *this;
718 };
719 
721 
722 bool MysqlDb::InputStart(const char* table,StDbBuffer *aBuff, const char* colList, int nRows,bool& hasBinary){
723 
724  bool tRetVal=false;
725  if(!table || !aBuff || !colList) return tRetVal;
726 
727  bool change=aBuff->IsClientMode();
728  if(change) aBuff->SetStorageMode();
729 
730  *this << "select * from " << table << " where null"<< endsql;
731  *this << "insert into " << table << " ("<<colList<<") VALUES(";
732  int i;
733 
734  char* tmpString=new char[strlen(colList)+1];
735  strcpy(tmpString,colList);
736  char *ptr1,*ptr2;
737  jfields=0;
738  bool done = false;
739  ptr1=tmpString;
740 
741  while(!done){
742  if((ptr2=strstr(ptr1,","))){
743  *ptr2='\0';
744  } else {
745  done=true;
746  }
747  if(*ptr1==' ')ptr1++;
748  if(cnames[jfields]) delete [] cnames[jfields];
749  cnames[jfields]=new char[strlen(ptr1)+1];
750  strcpy(cnames[jfields],ptr1);
751  if(!done){
752  ptr1=ptr2+1;
753  *ptr2=',';
754  }
755  jfields++;
756  }
757  delete [] tmpString;
758  int nfields=NbFields();
759  int fcount=0;
760  hasBinary=false;
761 
762  for(int k=0;k<jfields;k++){
763  for(i=0;i<nfields;i++)
764  if(strcmp(mRes->mRes->fields[i].name,cnames[k])==0)break;
765 
766  if(i==nfields)continue;
767  fcount++;
768  isBlob[k]=( (IS_BLOB(mRes->mRes->fields[i].flags)) ||
769  (mRes->mRes->fields[i].type ==254) );
770  isBinary[k]= (mRes->mRes->fields[i].flags&BINARY_FLAG);
771  isSpecialType[k]=(mRes->mRes->fields[i].type ==254);
772 
773  if(isBinary[k])hasBinary=true;
774  }
775  if(fcount!=jfields) done=false;
776 
777  return done;
778 
779 };
780 
781 bool MysqlDb::InputRow(StDbBuffer* aBuff, int row){
782 
783  char* tVal;tVal=0;
784  int len;
785  aBuff->SetStorageMode();
786  if(row>0)*this<<"),(";
787  int k;
788  for(k=0;k<jfields;k++){
789  if(k!=0)*this<<",";
790  if(isBlob[k]){
791  if(isBinary[k]){
792  if(!aBuff->ReadArray(tVal,len,cnames[k]))break;
793  *this<<"'"<<Binary(len,(float*)tVal)<<"'";
794  } else if(isSpecialType[k]) {
795  if(!aBuff->ReadScalar(tVal,cnames[k]))break;
796  *this<<"'"<<tVal<<"'";
797  } else {
798  char** tVal2=0;
799  if(!aBuff->ReadArray(tVal2,len,cnames[k]))break;
800  tVal=CodeStrArray(tVal2,len);
801  for(int jj=0;jj<len;jj++)if(tVal2[jj])delete []tVal2[jj];
802  *this<<"'"<<tVal<<"'";
803  }
804  } else {
805  if(!aBuff->ReadScalar(tVal,cnames[k])) break;
806  *this<<"'"<<tVal<<"'";
807  }
808  }
809 
810  aBuff->SetClientMode();
811 
812  if(k!=jfields){
813  RazQuery();
814  return false;
815  }
816 
817  return true;
818 }
819 
820 bool MysqlDb::InputEnd(){
821 
822 bool tRetVal=false;
823 *this<<")"<<endsql;
824 if(mqueryState)tRetVal=true;
825  return tRetVal;
826 
827 };
829 
830 bool MysqlDb::Input(const char *table,StDbBuffer *aBuff){
831  bool tRetVal=false;
832  bool change=aBuff->IsClientMode();
833  if (change) aBuff->SetStorageMode();
834  aBuff->SetStorageMode();
835  //if (aBuff) {
836  *this << "select * from " << table << " where null"<< endsql;
837  *this << "insert into " << table << " set ";
838  bool tFirst=true;
839  char* tVal;tVal=0;
840  int len;
841  unsigned i;
842 
843  for (i=0;i<NbFields();i++) {
844  if ((IS_BLOB(mRes->mRes->fields[i].flags) ) ||
845  mRes->mRes->fields[i].type ==254) {
846  if (mRes->mRes->fields[i].flags&BINARY_FLAG) { // Binary
847  if (aBuff->ReadArray(tVal,len,mRes->mRes->fields[i].name)){
848  if (tFirst) {
849  tFirst=false;
850  } else {
851  *this << ",";
852  };
853  *this << mRes->mRes->fields[i].name << "='" << Binary(len,(float*)tVal)<<"'";
854  };
855  }else{ // text types
856  if(mRes->mRes->fields[i].type==254){
857  if (aBuff->ReadScalar(tVal,mRes->mRes->fields[i].name)) {
858  if (tFirst) {
859  tFirst=false;
860  } else {
861  *this << ",";
862  };
863  *this << mRes->mRes->fields[i].name << "='" << tVal << "'";
864  };
865  } else {
866  char** tVal2=0;
867  if (aBuff->ReadArray(tVal2,len,mRes->mRes->fields[i].name)){
868  tVal=CodeStrArray(tVal2,len);
869  int j;for (j=0;j<len;j++) {if (tVal2[j]) delete [] tVal2[j];};
870  delete [] tVal2;
871  if (tFirst) {
872  tFirst=false;
873  } else {
874  *this << ",";
875  };
876  *this << mRes->mRes->fields[i].name << "='" << tVal<<"'";
877  }
878  };
879  };
880  } else { // not binary nor text
881  if (aBuff->ReadScalar(tVal,mRes->mRes->fields[i].name)) {
882  if (tFirst) {
883  tFirst=false;
884  } else {
885  *this << ",";
886  };
887  *this << mRes->mRes->fields[i].name << "='" << tVal << "'";
888  };
889  };
890  if (tVal) delete [] tVal;tVal=0;
891  };
892  if (tFirst) {
893  RazQuery();
894  } else {
895  *this << endsql;
896  if(mqueryState)tRetVal=true;
897  };
898  //};
899  // if (!tRetVal) cout << "insert Failed"<< endl;
900  if (change) aBuff->SetClientMode();
901  aBuff->SetClientMode();
902  return tRetVal;
903 };
904 
906 
907 bool MysqlDb::Output(StDbBuffer *aBuff){
908  //std::cout << "processing db: " << mdbName << ", query: " << mQuery << std::endl;
909 
910 
911  if (m_Mgr.isValueFound()) {
912  //std::cout << "Found value in cache! " << std::endl;
913  // process JSON data
914  return m_Mgr.processOutput(aBuff);
915  } else if (!m_Mgr.isValueFound() && mRes->mRes) {
916  if (!m_Mgr.getLastGroupKey().empty() && !m_Mgr.getLastKey().empty() && m_Mgr.getLastGroupKey() != " " && m_Mgr.getLastKey() != " ") {
917  //std::cout << "lastdb: " << m_Mgr.getLastGroupKey() << " | query: " << m_Mgr.getLastKey() << ", " << std::endl;
918 
919  aBuff->SetStorageMode();
920  m_Mgr.set(m_Mgr.getLastGroupKey().c_str(), m_Mgr.getLastKey().c_str(), mRes->mRes, 0);
921  mysql_data_seek(mRes->mRes, 0); // return to the beginning of result set..
922  aBuff->SetClientMode();
923  }
924  }
925 
926 
927  if(mlogTime)msocketLog.start();
928  MYSQL_ROW tRow=mysql_fetch_row(mRes->mRes);
929  if(!tRow) return false;
930  unsigned long * lengths=mysql_fetch_lengths(mRes->mRes);
931  unsigned tNbFields=NbFields();
932  if(mlogTime)msocketLog.end();
933  int i;
934  bool tRetVal=false;
935  bool change=aBuff->IsClientMode();
936  if (change) aBuff->SetStorageMode();
937  aBuff->SetStorageMode();
938 
939  for (i=0;i<(int)tNbFields;i++){
940  if(tRow[i]){
941 
942  // cout <<mRes->mRes->fields[i].name<<" = "<< tRow[i] << endl;
943  if (IS_BLOB(mRes->mRes->fields[i].flags)) {
944  if (mRes->mRes->fields[i].flags&BINARY_FLAG) {
945  aBuff->WriteArray((char*)tRow[i],lengths[i],mRes->mRes->fields[i].name);
946  }else {
947  char** tStrPtr;
948  int len;
949  tStrPtr=DecodeStrArray((char*)tRow[i],len);
950  aBuff->WriteArray(tStrPtr,len,mRes->mRes->fields[i].name);
951  for(int k=0;k<len;k++)delete [] tStrPtr[k];
952  delete [] tStrPtr;
953 
954  // something of a cludge: "," are used in "Decode.."
955  // as array delimeters. But we also want to have
956  // char arrays for comment structures - so write'em both
957  // to the buffer.
958 
959  //char commentName[1024];
960  StString cn;
961  cn<<mRes->mRes->fields[i].name<<".text";
962  aBuff->WriteScalar((char*)tRow[i],(cn.str()).c_str());
963  };
964  } else {
965  aBuff->WriteScalar((char*)tRow[i],mRes->mRes->fields[i].name);
966  };
967  }
968 
969  /*
970  else {
971 
972  StString nd;
973  nd<<"null data returned from table = ";
974  nd<<mRes->mRes->fields[i].table<<" column="<<mRes->mRes->fields[i].name;
975  StDbManager::Instance()->printInfo((nd.str()).c_str(),dbMWarn,__LINE__,"MysqlDb","Output(StDbBuffer* b)");
976  }
977  */
978 
979  tRetVal=true;
980  };
981  if (change) aBuff->SetClientMode();
982  aBuff->SetClientMode();
983  return tRetVal;
984 }
985 
987 
988 char** MysqlDb::DecodeStrArray(char* strinput , int &aLen){
989 
990  if(!strinput){ // shouldn't happen - should have checked before here
991  // cout<< "null input string from mysql " << endl;
992  char** tmparr = new char*[1];
993  aLen = 1;
994  //*tmparr = new char[2];
995  //strcpy(*tmparr,"0");
996  tmparr[0] = (char*)"0";
997  return tmparr;
998  }
999 
1000  char* tPnt=strinput;
1001  aLen=0;
1002  //MPD: bumped this limit up from 100 for the 768 ssd strips - with fingers crossed
1003  while (tPnt&&aLen<1024) { // 1024 is a limit on # comma separated values
1004  tPnt=strpbrk( tPnt,"\\,");
1005  if (tPnt!=0){
1006  if (*tPnt==',') {
1007  aLen++;tPnt++;
1008  } else { //(*tPnt=='\\')
1009  tPnt++;tPnt++;};
1010  };
1011  };
1012  aLen++;
1013  char** strarr=new char*[aLen];
1014  tPnt=strinput;
1015  char* tPntNew=tPnt;
1016  char *tBuff=new char[strlen(strinput)+1];
1017  char *tBuffInd=tBuff;
1018  int tCount=0;
1019  while (tPntNew) {
1020  tPntNew=strpbrk( tPnt,"\\,");
1021  if ((tPntNew==0)||*tPntNew==',') {
1022  if (tPntNew==0) {
1023  strcpy(tBuffInd,tPnt);
1024 
1025  } else {
1026  strncpy(tBuffInd,tPnt,tPntNew-tPnt);
1027  *(tBuffInd+(tPntNew-tPnt))='\0';
1028  }
1029  strarr[tCount]=new char[strlen(tBuff)+1];
1030  strcpy(strarr[tCount],tBuff);
1031  tBuffInd=tBuff;
1032  tPnt=tPntNew+1;
1033  tCount++;
1034  } else { //(*tPntNew=='\\')
1035  strncpy(tBuffInd,tPnt,tPntNew-tPnt);
1036  tBuffInd=tBuffInd+(tPntNew-tPnt);
1037  tPntNew++;
1038  if(*tPntNew=='\\'||*tPntNew==',') {
1039  *tBuffInd=*tPntNew;
1040  tBuffInd++;
1041  };
1042  *(tBuffInd)='\0';
1043  tPnt=tPntNew+1;
1044  };
1045  };
1046  delete [] tBuff;
1047  return strarr;
1048 }
1049 
1051 
1052 char* MysqlDb::CodeStrArray(char** strarr , int aLen){
1053  int tMaxLen=0;
1054  int i;
1055  for (i=0;i<aLen;i++) {
1056  if (strarr[i]) tMaxLen=tMaxLen+strlen(strarr[i])*2;
1057  tMaxLen++;
1058  };
1059  char* tTempVal=new char[tMaxLen+1];
1060  char* tRead;
1061  char* tWrite=tTempVal;
1062  for (i=0;i<aLen;i++) {
1063  if (strarr[i]){
1064  int j;
1065  tRead=strarr[i];
1066  for (j=0;j<(int)strlen(strarr[i]);j++) {
1067  if (*tRead=='\\'||*tRead==',') {
1068  *tWrite='\\';
1069  tWrite++;
1070  };
1071  *tWrite=*tRead;
1072  tWrite++;
1073  tRead++;
1074  };
1075  };
1076  *tWrite=',';
1077  tWrite++;
1078  };
1079  tWrite--;
1080  *tWrite='\0';
1081  char *tRetVal=new char[strlen(tTempVal)+1];
1082  strcpy(tRetVal,tTempVal);
1083  delete [] tTempVal;
1084  return tRetVal;
1085 };
1086 
1088 
1089 bool
1090 MysqlDb::setDefaultDb(const char* dbName){
1091 
1092  if(!dbName || strlen(dbName)==0)return false;
1093 if(mdbName) delete [] mdbName;
1094 mdbName=new char[strlen(dbName)+1];
1095 strcpy(mdbName,dbName);
1096 if(strcmp(dbName," ")==0)return true;
1097 
1098 bool tOk=false;
1099 unsigned int mysqlError;
1100 std::string sdbName(dbName);
1101 size_t found;
1102 found = sdbName.find("blacklist");
1103 
1104  if(mysql_select_db(&mData,dbName)){
1105 
1106  mysqlError = mysql_errno(&mData);
1107  if(mysqlError==CR_SERVER_GONE_ERROR || mysqlError==CR_SERVER_LOST){
1108  reConnect();
1109  if(mysql_select_db(&mData,dbName)){
1110  if (found == std::string::npos) {
1111  LOG_ERROR<< "Error selecting database=" << dbName << endm;
1112  }
1113  tOk=false;
1114  } else {
1115  tOk=true;
1116  }
1117  } else {
1118  if (found == std::string::npos) {
1119  LOG_ERROR<< "Error selecting database=" << dbName << endm;
1120  }
1121  tOk=false;
1122  }
1123  } else {
1124  tOk=true;
1125  }
1126 
1127 return tOk;
1128 }
1129 
1131 
1132 const MysqlBin *Binary(const unsigned long int aLen,const float *aBin){
1133  static MysqlBin *tBin=0;
1134  static char *tString=0;
1135  unsigned long int tNewLen;
1136 
1137  if (!tBin) tBin=new MysqlBin;
1138  if (tString) delete [] tString;
1139 
1140  tString = new char[2*aLen+1];
1141  tNewLen = mysql_escape_string(tString,(char*) aBin,aLen);
1142  tBin->Input(tNewLen,tString);
1143  return tBin;
1144 }
1145 
1146 #undef __CLASS__
1147 
1148 
static StDbManager * Instance()
strdup(..) is not ANSI
Definition: StDbManager.cc:155