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