00001 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 #include <stdio.h>
00033 #ifdef _WIN32
00034 #pragma warning(disable:4786)
00035 #endif
00036 
00037 #include <string>
00038 #include <map>
00039 #ifdef WIN32
00040 #include <config-win.h>
00041 #include <mysql.h>
00042 #else
00043 #include <stdio.h>
00044 #include <stdlib.h>
00045 #include <string.h>
00046 #include <mysql/mysql.h>
00047 #include <stdarg.h>
00048 #endif
00049 
00050 #include "IError.h"
00051 #include "Database.h"
00052 
00053 
00054 #ifdef MYSQLW_NAMESPACE
00055 namespace MYSQLW_NAMESPACE {
00056 #endif
00057 
00058 
00059 Database::Database(const std::string& d,IError *e)
00060 :database(d)
00061 ,m_errhandler(e)
00062 ,m_embedded(true)
00063 ,m_mutex(m_mutex)
00064 ,m_b_use_mutex(false)
00065 {
00066 }
00067 
00068 
00069 Database::Database(Mutex& m,const std::string& d,IError *e)
00070 :database(d)
00071 ,m_errhandler(e)
00072 ,m_embedded(true)
00073 ,m_mutex(m)
00074 ,m_b_use_mutex(true)
00075 {
00076 }
00077 
00078 
00079 Database::Database(const std::string& h,const std::string& u,const std::string& p,const std::string& d,IError *e)
00080 :host(h)
00081 ,user(u)
00082 ,password(p)
00083 ,database(d)
00084 ,m_errhandler(e)
00085 ,m_embedded(false)
00086 ,m_mutex(m_mutex)
00087 ,m_b_use_mutex(false)
00088 {
00089 }
00090 
00091 
00092 Database::Database(Mutex& m,const std::string& h,const std::string& u,const std::string& p,const std::string& d,IError *e)
00093 :host(h)
00094 ,user(u)
00095 ,password(p)
00096 ,database(d)
00097 ,m_errhandler(e)
00098 ,m_embedded(false)
00099 ,m_mutex(m)
00100 ,m_b_use_mutex(true)
00101 {
00102 }
00103 
00104 
00105 Database::~Database()
00106 {
00107         for (opendb_v::iterator it = m_opendbs.begin(); it != m_opendbs.end(); it++)
00108         {
00109                 OPENDB *p = *it;
00110                 mysql_close(&p -> mysql);
00111         }
00112         while (m_opendbs.size())
00113         {
00114                 opendb_v::iterator it = m_opendbs.begin();
00115                 OPENDB *p = *it;
00116                 if (p -> busy)
00117                 {
00118                         error("destroying Database object before Query object");
00119                 }
00120                 delete p;
00121                 m_opendbs.erase(it);
00122         }
00123 }
00124 
00125 
00126 void Database::OnMyInit(OPENDB *odb)
00127 {
00128         
00129         if (m_embedded)
00130         {
00131                 mysql_options(&odb -> mysql, MYSQL_READ_DEFAULT_GROUP, "test_libmysqld_CLIENT");
00132         }
00133 }
00134 
00135 
00136 void Database::RegErrHandler(IError *p)
00137 {
00138         m_errhandler = p;
00139 }
00140 
00141 
00142 Database::OPENDB *Database::grabdb()
00143 {
00144         Lock lck(m_mutex, m_b_use_mutex);
00145         OPENDB *odb = NULL;
00146 
00147         for (opendb_v::iterator it = m_opendbs.begin(); it != m_opendbs.end(); it++)
00148         {
00149                 odb = *it;
00150                 if (!odb -> busy)
00151                 {
00152                         break;
00153                 }
00154                 else
00155                 {
00156                         odb = NULL;
00157                 }
00158         }
00159         if (!odb)
00160         {
00161                 odb = new OPENDB;
00162                 if (!odb)
00163                 {
00164                         error("grabdb: OPENDB struct couldn't be created");
00165                         return NULL;
00166                 }
00167                 if (!mysql_init(&odb -> mysql))
00168                 {
00169                         error("mysql_init() failed - list size %d",m_opendbs.size());
00170                         delete odb;
00171                         return NULL;
00172                 }
00173                 
00174                 this -> OnMyInit(odb);
00175                 if (m_embedded)
00176                 {
00177                         if (!mysql_real_connect(&odb -> mysql,NULL,NULL,NULL,database.c_str(),0,NULL,0) )
00178                         {
00179                                 error("mysql_real_connect(NULL,NULL,NULL,%s,0,NULL,0) failed - list size %d",database.c_str(),m_opendbs.size());
00180                                 delete odb;
00181                                 return NULL;
00182                         }
00183                 }
00184                 else
00185                 {
00186                         if (!mysql_real_connect(&odb -> mysql,host.c_str(),user.c_str(),password.c_str(),database.c_str(),0,NULL,0) )
00187                         {
00188                                 error("mysql_real_connect(%s,%s,***,%s,0,NULL,0) failed - list size %d",host.c_str(),user.c_str(),database.c_str(),m_opendbs.size());
00189                                 delete odb;
00190                                 return NULL;
00191                         }
00192                 }
00193                 odb -> busy = true;
00194                 m_opendbs.push_back(odb);
00195         }
00196         else
00197         {
00198                 if (mysql_ping(&odb -> mysql))
00199                 {
00200                         error("mysql_ping() failed when reusing an old connection from the connection pool");
00201                 }
00202                 odb -> busy = true;
00203         }
00204         return odb;
00205 }
00206 
00207 
00208 void Database::freedb(Database::OPENDB *odb)
00209 {
00210         Lock lck(m_mutex, m_b_use_mutex);
00211         if (odb)
00212         {
00213                 odb -> busy = false;
00214         }
00215 }
00216 
00217 
00218 void Database::error(const char *format, ...)
00219 {
00220         if (m_errhandler)
00221         {
00222                 va_list ap;
00223                 char errstr[5000];
00224                 va_start(ap, format);
00225 #ifdef WIN32
00226                 vsprintf(errstr, format, ap);
00227 #else
00228                 vsnprintf(errstr, 5000, format, ap);
00229 #endif
00230                 va_end(ap);
00231                 m_errhandler -> error(*this, errstr);
00232         }
00233 }
00234 
00235 
00236 void Database::error(Query& q,const char *format, ...)
00237 {
00238         if (m_errhandler)
00239         {
00240                 va_list ap;
00241                 char errstr[5000];
00242                 va_start(ap, format);
00243 #ifdef WIN32
00244                 vsprintf(errstr, format, ap);
00245 #else
00246                 vsnprintf(errstr, 5000, format, ap);
00247 #endif
00248                 va_end(ap);
00249                 m_errhandler -> error(*this, q, errstr);
00250         }
00251 }
00252 
00253 
00254 bool Database::Connected()
00255 {
00256         OPENDB *odb = grabdb();
00257         if (!odb)
00258         {
00259                 return false;
00260         }
00261         int ping_result = mysql_ping(&odb -> mysql);
00262         if (ping_result)
00263         {
00264                 error("mysql_ping() failed");
00265         }
00266         freedb(odb);
00267         return ping_result ? false : true;
00268 }
00269 
00270 
00271 Database::Lock::Lock(Mutex& mutex,bool use) : m_mutex(mutex),m_b_use(use) 
00272 {
00273         if (m_b_use) 
00274         {
00275                 m_mutex.Lock();
00276         }
00277 }
00278 
00279 
00280 Database::Lock::~Lock() 
00281 {
00282         if (m_b_use) 
00283         {
00284                 m_mutex.Unlock();
00285         }
00286 }
00287 
00288 
00289 Database::Mutex::Mutex()
00290 {
00291 #ifdef _WIN32
00292         m_mutex = ::CreateMutex(NULL, FALSE, NULL);
00293 #else
00294         pthread_mutex_init(&m_mutex, NULL);
00295 #endif
00296 }
00297 
00298 
00299 Database::Mutex::~Mutex()
00300 {
00301 #ifdef _WIN32
00302         ::CloseHandle(m_mutex);
00303 #else
00304         pthread_mutex_destroy(&m_mutex);
00305 #endif
00306 }
00307 
00308 
00309 void Database::Mutex::Lock()
00310 {
00311 #ifdef _WIN32
00312         DWORD d = WaitForSingleObject(m_mutex, INFINITE);
00313         
00314 #else
00315         pthread_mutex_lock(&m_mutex);
00316 #endif
00317 }
00318 
00319 
00320 void Database::Mutex::Unlock()
00321 {
00322 #ifdef _WIN32
00323         ::ReleaseMutex(m_mutex);
00324 #else
00325         pthread_mutex_unlock(&m_mutex);
00326 #endif
00327 }
00328 
00329 
00330 std::string Database::safestr(const std::string& str)
00331 {
00332         std::string str2;
00333         for (size_t i = 0; i < str.size(); i++)
00334         {
00335                 switch (str[i])
00336                 {
00337                 case '\'':
00338                 case '\\':
00339                 case 34:
00340                         str2 += '\\';
00341                 default:
00342                         str2 += str[i];
00343                 }
00344         }
00345         return str2;
00346 }
00347 
00348 
00349 std::string Database::unsafestr(const std::string& str)
00350 {
00351         std::string str2;
00352         for (size_t i = 0; i < str.size(); i++)
00353         {
00354                 if (str[i] == '\\')
00355                 {
00356                         i++;
00357                 }
00358                 if (i < str.size())
00359                 {
00360                         str2 += str[i];
00361                 }
00362         }
00363         return str2;
00364 }
00365 
00366 
00367 std::string Database::xmlsafestr(const std::string& str)
00368 {
00369         std::string str2;
00370         for (size_t i = 0; i < str.size(); i++)
00371         {
00372                 switch (str[i])
00373                 {
00374                 case '&':
00375                         str2 += "&";
00376                         break;
00377                 case '<':
00378                         str2 += "<";
00379                         break;
00380                 case '>':
00381                         str2 += ">";
00382                         break;
00383                 case '"':
00384                         str2 += """;
00385                         break;
00386                 case '\'':
00387                         str2 += "'";
00388                         break;
00389                 default:
00390                         str2 += str[i];
00391                 }
00392         }
00393         return str2;
00394 }
00395 
00396 
00397 int64_t Database::a2bigint(const std::string& str)
00398 {
00399         int64_t val = 0;
00400         bool sign = false;
00401         size_t i = 0;
00402         if (str[i] == '-')
00403         {
00404                 sign = true;
00405                 i++;
00406         }
00407         for (; i < str.size(); i++)
00408         {
00409                 val = val * 10 + (str[i] - 48);
00410         }
00411         return sign ? -val : val;
00412 }
00413 
00414 
00415 uint64_t Database::a2ubigint(const std::string& str)
00416 {
00417         uint64_t val = 0;
00418         for (size_t i = 0; i < str.size(); i++)
00419         {
00420                 val = val * 10 + (str[i] - 48);
00421         }
00422         return val;
00423 }
00424 
00425 
00426 #ifdef MYSQLW_NAMESPACE
00427 } 
00428 #endif
00429