Forums  +  C++ and Sockets  +  C++ and SQL: MySQL, sqlite, ODBC  +  Miscellaneous Projects
Logo
~Database~
~ C++ ~
~Contact~

Database.cpp

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2001  Anders Hedstrom
00009 
00010 This program is made available under the terms of the GNU GPL.
00011 
00012 If you would like to use this program in a closed-source application,
00013 a separate license agreement is available. For information about 
00014 the closed-source license agreement for this program, please
00015 visit http://www.alhem.net/sqlwrapped/license.html and/or
00016 email license@alhem.net.
00017 
00018 This program is free software; you can redistribute it and/or
00019 modify it under the terms of the GNU General Public License
00020 as published by the Free Software Foundation; either version 2
00021 of the License, or (at your option) any later version.
00022 
00023 This program is distributed in the hope that it will be useful,
00024 but WITHOUT ANY WARRANTY; without even the implied warranty of
00025 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00026 GNU General Public License for more details.
00027 
00028 You should have received a copy of the GNU General Public License
00029 along with this program; if not, write to the Free Software
00030 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
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         // using embedded server (libmysqld)
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                 // use callback to set mysql_options() before connect, etc
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         // %! check 'd' for result
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 += "&amp;";
00376                         break;
00377                 case '<':
00378                         str2 += "&lt;";
00379                         break;
00380                 case '>':
00381                         str2 += "&gt;";
00382                         break;
00383                 case '"':
00384                         str2 += "&quot;";
00385                         break;
00386                 case '\'':
00387                         str2 += "&apos;";
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 } // namespace MYSQLW_NAMESPACE {
00428 #endif
00429 
Page, code, and content Copyright (C) 2006 by Anders Hedström