nmysql.cpp

00001 // LICENSE: (Please see the file COPYING for details)
00002 //
00003 // NUS - Nemesis Utilities System: A C++ application development framework 
00004 // Copyright (C) 2006, 2008 Otavio Rodolfo Piske
00005 //
00006 //  This file is part of NUS
00007 //
00008 //  This library is free software; you can redistribute it and/or
00009 //  modify it under the terms of the GNU Lesser General Public
00010 //  License as published by the Free Software Foundation version 2.1
00011 //  of the License.
00012 //
00013 //  This library is distributed in the hope that it will be useful,
00014 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00015 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00016 //  Lesser General Public License for more details.
00017 //
00018 //  You should have received a copy of the GNU Lesser General Public
00019 //  License along with this library; if not, write to the Free Software
00020 //  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00021 //
00022 #include "nmysql.h"
00023 
00024 NMySql::NMySql(void)
00025       : NSql(),
00026       m_handle(NULL),
00027       m_resultSet(),
00028       m_pos(0),
00029       m_connected(false)
00030 { 
00031       init();
00032 } 
00033 
00034 NMySql::NMySql(const NString &user, const NString &pass, 
00035       const NHostAddress &host)
00036       : NSql(user, pass, host),
00037       m_handle(NULL),
00038       m_resultSet(),
00039       m_pos(0)
00040 { 
00041       init();
00042 }
00043 
00044 
00045 NMySql::NMySql(const NString &user, const NString &pass, 
00046       const NHostAddress &host, nint16 port)
00047       : NSql(user, pass, host, port),
00048       m_handle(NULL),
00049       m_resultSet(),
00050       m_pos(0)
00051 {
00052       init();
00053 }
00054 
00055 
00056 NMySql::~NMySql(void) { 
00057       disconnectFromHost();
00058       mysql_library_end();
00059       m_handle = NULL;
00060 }
00061 
00062 void NMySql::init(void) { 
00063       m_handle = mysql_init(NULL);
00064       if (!m_handle) { 
00065             throw NMemException("Not enough memory to initialize MySql driver",
00066                   NException::DBAL);
00067       }
00068 }
00069 
00070 NString NMySql::getError(void) const {
00071       nuint32 err_val = 0;
00072       NString ret = "";
00073       
00074 
00075       err_val = mysql_errno(m_handle);
00076       switch (err_val) { 
00077             case CR_SOCKET_CREATE_ERROR: { 
00078                   ret = "Can't create socket";
00079                   break;
00080             }
00081             case CR_CONNECTION_ERROR: { 
00082                   ret = "Can't connect to local server at ";
00083                   ret += m_host.toString();
00084                   break;
00085             }
00086             case CR_CONN_HOST_ERROR: { 
00087                   ret = "Can't connect to server at ";
00088                   ret += m_host.toString();
00089                   break;
00090             }
00091             case CR_IPSOCK_ERROR: { 
00092                   ret = "Can't create TPC/IP socket";
00093                   break;
00094             }
00095             case CR_UNKNOWN_HOST: { 
00096                   ret = "Unknown host: ";
00097                   ret += m_host.toString();
00098                   break;
00099             }
00100             case CR_SERVER_GONE_ERROR: { 
00101                   ret = "The server has gone away or quit";
00102                   break;
00103             }
00104             case CR_VERSION_ERROR: { 
00105                   ret = "Protocol mismatch between server and client";
00106                   ret += getDetailedError();
00107                   break;
00108             }
00109             case CR_OUT_OF_MEMORY: { 
00110                   ret = "Client do not have enough memory to complete the request";
00111                   break;
00112             }
00113             case CR_WRONG_HOST_INFO: { 
00114                   ret = "Wrong host info";
00115                   break;
00116             }
00117             case CR_LOCALHOST_CONNECTION: { 
00118                   ret = "Localhost via unix socket";
00119                   break;
00120             }
00121             case CR_TCP_CONNECTION: { 
00122                   ret = "TCP connection error";
00123                   ret += getDetailedError();
00124                   break;
00125             }
00126             case CR_SERVER_HANDSHAKE_ERR: { 
00127                   ret = "Connection handshake error";
00128                   break;
00129             }
00130             case CR_SERVER_LOST: { 
00131                   ret = "Lost connection with MySQL server during query";
00132                   break;
00133             }
00134             case CR_COMMANDS_OUT_OF_SYNC: { 
00135                   ret = "Commands out of sync. You can't run this command now";
00136                   break;
00137             }
00138             case CR_NAMEDPIPE_CONNECTION: 
00139             case CR_NAMEDPIPEWAIT_ERROR: 
00140             case CR_NAMEDPIPEOPEN_ERROR:
00141             case CR_NAMEDPIPESETSTATE_ERROR: { 
00142                   ret = "Unknown named pipe error: ";
00143                   ret += getDetailedError();
00144                   break;
00145             }
00146             
00147             case CR_CANT_READ_CHARSET: { 
00148                   ret = "Can't initialize charset: ";
00149                   ret += getDetailedError();
00150                   break;
00151             }
00152             case CR_NET_PACKET_TOO_LARGE: { 
00153                   ret = "Got packet bigger than 'max_allowed_bytes'";
00154                   break;
00155             }
00156             case CR_EMBEDDED_CONNECTION: { 
00157                   ret = "Embedded connection error";
00158                   ret += getDetailedError();
00159                   break;
00160             }
00161             case CR_PROBE_SLAVE_STATUS: { 
00162                   ret = "Error on SHOW SLAVE STATUS";
00163                   break;
00164             }
00165             case CR_PROBE_SLAVE_HOSTS: { 
00166                   ret = "Error on SHOW SLAVE HOSTS";
00167                   break;
00168             }
00169             case CR_PROBE_SLAVE_CONNECT: { 
00170                   ret = "Error connecting to slave";
00171                   break;
00172             }
00173             case CR_PROBE_MASTER_CONNECT: { 
00174                   ret = "Error connecting to master";
00175                   break;
00176             }
00177             case CR_SSL_CONNECTION_ERROR: { 
00178                   ret = "SSL connection error";
00179                   break;
00180             }
00181             case CR_MALFORMED_PACKET: { 
00182                   ret = "Malformed packet";
00183                   ret += getDetailedError();
00184                   break;
00185             }
00186             case CR_WRONG_LICENSE: { 
00187                   ret = "This client library is not licensed for use with";
00188                   ret += " the current server";
00189                   break;
00190             }
00191             case CR_NULL_POINTER: { 
00192                   ret = "Invalid use of NULL pointer";
00193                   break;
00194             }
00195             case CR_NO_PREPARE_STMT: { 
00196                   ret = "Statement not prepared";
00197                   break;
00198             }
00199             case CR_PARAMS_NOT_BOUND: { 
00200                   ret = "No data supplied for parameters in prepared statement";
00201                   break;
00202             }
00203             case CR_DATA_TRUNCATED: { 
00204                   ret = "Data truncated";
00205                   ret += getDetailedError();
00206                   break;
00207             }
00208             case CR_NO_PARAMETERS_EXISTS: { 
00209                   ret = "No parameters exist in statement";
00210                   break;
00211             }
00212             case CR_INVALID_PARAMETER_NO: { 
00213                   ret = "Invalid parameter number";
00214                   break;
00215             }
00216             case CR_INVALID_BUFFER_USE: { 
00217                   ret = "Can't send long data";
00218                   ret += getDetailedError();
00219                   break;
00220             }
00221             case CR_UNSUPPORTED_PARAM_TYPE: { 
00222                   ret = "Unsupported param type";
00223                   break;
00224             }
00225             case CR_SHARED_MEMORY_CONNECTION: 
00226             case CR_SHARED_MEMORY_CONNECT_REQUEST_ERROR: 
00227             case CR_SHARED_MEMORY_CONNECT_ANSWER_ERROR: 
00228             case CR_SHARED_MEMORY_CONNECT_FILE_MAP_ERROR: 
00229             case CR_SHARED_MEMORY_CONNECT_MAP_ERROR: 
00230             case CR_SHARED_MEMORY_FILE_MAP_ERROR: 
00231             case CR_SHARED_MEMORY_MAP_ERROR: 
00232             case CR_SHARED_MEMORY_EVENT_ERROR: 
00233             case CR_SHARED_MEMORY_CONNECT_ABANDONED_ERROR: 
00234             case CR_SHARED_MEMORY_CONNECT_SET_ERROR: { 
00235                   ret = "Shared memory error: ";
00236                   ret += getDetailedError();
00237                   break;
00238             }
00239             case CR_CONN_UNKNOW_PROTOCOL: { 
00240                   ret = "Wrong or unknown protocol";
00241                   break;
00242             }
00243             case CR_INVALID_CONN_HANDLE: { 
00244                   ret = "Invalid connection handle";
00245                   break;
00246             }
00247             case CR_SECURE_AUTH: { 
00248                   ret = "Connection using old (pre-4.1.1) authentication";
00249                   ret += " protocol refused";
00250                   break;
00251             }
00252             case CR_FETCH_CANCELED: { 
00253                   ret = "Row retrieval was canceled";
00254                   break;
00255             }
00256             case CR_NO_DATA: { 
00257                   ret = "Attempt to read column without prior fetch";
00258                   break;
00259             }
00260             case CR_NO_STMT_METADATA: { 
00261                   ret = "Prepared statement contains no metadata";
00262                   break;
00263             }
00264             case CR_NO_RESULT_SET: { 
00265                   ret = "Attempt to read a row without an associated result set";
00266                   break;
00267             }
00268             case CR_NOT_IMPLEMENTED: { 
00269                   ret = "This feature is not implemented yet";
00270                   break;
00271             }
00272             case CR_SERVER_LOST_EXTENDED: { 
00273                   ret = "Lost connection with server at ";
00274                   ret = ret + m_host.toString() + ". ";
00275                   ret += getDetailedError();
00276 
00277                   break;
00278             }
00279             case CR_UNKNOWN_ERROR: 
00280             default: { 
00281                   ret = "Unknown error: ";
00282                   ret += getDetailedError();
00283                   break;
00284             }     
00285       }
00286 
00287       return ret;
00288 }
00289 
00290 NString NMySql::getDetailedError(void) const {
00291       NString ret; 
00292       const char *details = NULL; 
00293       
00294       details = mysql_error(m_handle);
00295       if (details) { 
00296             ret = "MySQL error message is: ";
00297             ret += details;
00298       }
00299 
00300       return ret;
00301 }
00302 
00303 
00304 void NMySql::connectToHost(void) { 
00305       MYSQL *ret = NULL;
00306 
00307       if (!m_handle) { 
00308             throw NException("You don't have setup a DB connection", 
00309                   NException::DBAL);
00310       }
00311 
00312       m_host.resolve();
00313       NDebug::print() << "Connecting to: " << m_host.toString();
00314       NDebug::print() << "User: " << m_user;
00315       NDebug::print() << "Port: " << m_port;
00316       NDebug::print() << "Database: " << m_database;
00317 
00318       ret = mysql_real_connect(m_handle, m_host.toString().toChar(),
00319             m_user.toChar(), m_password.toChar(), m_database.toChar(), 
00320             m_port, NULL, 0);
00321 
00322       if (ret != m_handle) {
00323             throw NException(getError(), NException::DBAL);
00324       }
00325 
00326       m_connected = true;
00327       
00328 }
00329 
00330 
00331 void NMySql::disconnectFromHost(void) { 
00332       if (m_handle) { 
00333             mysql_close(m_handle);
00334       }
00335 
00336       
00337       m_connected = false;
00338 }
00339 
00340 
00341 bool NMySql::execSql(const NSqlQuery &query) { 
00342       nint32 ret = 0;
00343       NString statement;
00344 
00345       if (!m_connected) { 
00346             throw NException("You don't have setup a DB connection", 
00347                   NException::DBAL);
00348       }
00349 
00350       statement = query.get();
00351 
00352       ret = mysql_query(m_handle, statement.toChar());
00353       if (ret != 0) {
00354             NDebug::print() << "Error executing last statement: " 
00355                   << getDetailedError();
00356             
00357             return false;
00358       }
00359 
00360       loadResultSet();
00361       return true;
00362 }
00363 
00364 void NMySql::clearResultSet(void) {
00365       NSqlRecord *rec = NULL;
00366 
00367       // We use use m_resultSet.size() instead of (m_resultSet.size() - 2)
00368       // because the EOD terminators will be re-placed at the end of this 
00369       // method.
00370       for (nuint64 i = 0; i < m_resultSet.size(); i++) { 
00371             rec = m_resultSet.at(i);      
00372             delete rec;
00373       }
00374 
00375       m_resultSet.clear();
00376       m_resultSet.append(NULL);
00377 }
00378 
00379 NSqlRecord *NMySql::loadRow(MYSQL_RES *result, MYSQL_ROW row) {
00380       NSqlRecord *ret = NULL;
00381       MYSQL_FIELD *fields = NULL;
00382       nuint32 num_fields = 0;
00383 
00384       num_fields = mysql_num_fields(result);
00385       fields = mysql_fetch_fields(result);
00386       if (num_fields > 0) { 
00387             ret = new NSqlRecord;
00388       
00389             for (nuint32 i = 0; i < num_fields; i++) { 
00390                   NString tmp = row[i];
00391                   
00392       
00393                   NString name(fields[i].name);
00394                   NVtype rowData(tmp);
00395       
00396                   NDebug::print() << "Pass " << i << " loaded field " << name 
00397                         << " with data " << rowData.toString();
00398       
00399                   NSql::setRecordData(ret, name, rowData);
00400             }
00401       }
00402       
00403       
00404       return ret;
00405 }
00406 
00407 void NMySql::loadResultSet(void) { 
00408       MYSQL_RES *result = NULL;
00409       MYSQL_ROW row;
00410 
00411       my_ulonglong count = 0;
00412       
00413       count = mysql_affected_rows(m_handle);
00414       NDebug::print() << "Affected rows: " << count;
00415       
00416       result = mysql_store_result(m_handle);
00417       if (!result) { 
00418             if (mysql_field_count(m_handle) > 0) {
00419                   throw NException(getError(), NException::DBAL);
00420             }
00421       }
00422       else {
00423             clearResultSet();
00424             while ((row = mysql_fetch_row(result))) { 
00425                   m_resultSet.append(loadRow(result, row));
00426             };
00427             m_resultSet.append(NULL);
00428             mysql_free_result(result);
00429       }
00430 }
00431 
00432 NSqlRecord *NMySql::getNext(void) { 
00433       // It uses (m_resultSet.size() - 2) because the start of data and 
00434       // end of data place holders.
00435       NDebug::print() << "Recordset position: " << m_pos << " of " 
00436             << (m_resultSet.size() - 2);
00437 
00438       if (m_resultSet.size() > 0 && m_pos < (m_resultSet.size() - 2)) {
00439             m_pos++;
00440             return m_resultSet.at(m_pos);
00441       }
00442 
00443       return NULL;
00444 }
00445 
00446 
00447 NSqlRecord *NMySql::getPrevious(void) { 
00448       if (m_pos != 0) {
00449             m_pos--;
00450             return m_resultSet.at(m_pos);
00451             
00452       }
00453 
00454       return NULL;
00455 }
00456 
00457 
00458 NSqlRecord *NMySql::getFirst(void) { 
00459       // It uses (m_resultSet.size() - 2) because the start of data and 
00460       // end of data place holders.
00461       if ((m_resultSet.size() - 2) > 0) {
00462             m_pos++;
00463             return m_resultSet.at(1);
00464       }
00465 
00466       return NULL;
00467 }
00468 
00469 
00470 NSqlRecord *NMySql::getLast(void) { 
00471       return m_resultSet.last();
00472 }

Generated on Wed Mar 5 23:10:35 2008 for NemesisUtilitiesSystem by  doxygen 1.5.4