00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
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
00368
00369
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
00434
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
00460
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 }