├── Documentation.pdf ├── README.md ├── mysqlquery.h └── mysqlquery.cpp /Documentation.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/flurreh/mysqlquerypp/HEAD/Documentation.pdf -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | MySQLQueryPP 2 | ========== 3 | 4 | A C++ MySQL Query/Connection class which uses the C-Connector 5 | -------------------------------------------------------------------------------- /mysqlquery.h: -------------------------------------------------------------------------------- 1 | #ifndef MYSQLQUERY_H 2 | #define MYSQLQUERY_H 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | class MySQLConnection 12 | { 13 | 14 | public: 15 | MySQLConnection(); 16 | ~MySQLConnection(); 17 | // connects to a MySQL-server 18 | bool Connect(const std::string &sHostname, const uint16_t &wPort, const std::string &sUsername, const std::string &sPassword, const std::string &sDB); 19 | // selects a DB 20 | bool SelectDB(const std::string &sSchemaName); 21 | // disconnects (huh, who guessed this?) 22 | void Disconnect(); 23 | // returns the last error string 24 | const std::string GetLastError() const; 25 | // gets a pointer to the MySQL connection 26 | MYSQL *getConn(); 27 | // returns true when connected 28 | bool IsConnected(); 29 | // returns an escaped string 30 | const std::string EscapeString(const std::string &value) const; 31 | 32 | private: 33 | MYSQL *m_MySQLConn; 34 | bool m_bIsConnected; 35 | std::string m_sHostname; 36 | std::string m_sUsername; 37 | std::string m_sPassword; 38 | std::string m_sSchemaName; 39 | uint16_t m_wPort; 40 | }; 41 | 42 | class MySQLQuery 43 | { 44 | 45 | public: 46 | 47 | MySQLQuery(MySQLConnection *mConn, const std::string &sStatement); 48 | ~MySQLQuery(); 49 | 50 | // sets the value of idx to a given string (also adds quotation marks and escapes the string) 51 | bool setString(const unsigned int &idx, const std::string &value); 52 | // sets the value of idx to a given int 53 | bool setInt(const unsigned int &idx, const int &value); 54 | // sets the value of idx to a given double 55 | bool setDouble(const unsigned int &idx, const double &value); 56 | // sets the value of idx to a given time_t 57 | bool setTime(const unsigned int &idx, const time_t &value); 58 | // sets the value of idx to NULL 59 | bool setNull(const unsigned int &idx); 60 | 61 | // executes a SELECT-statement 62 | bool ExecuteQuery(); 63 | // executes an UPDATE-statement 64 | bool ExecuteUpdate(); 65 | // executes an INSERT-statement and returns the last inserted ID 66 | int ExecuteInsert(); 67 | 68 | // builds the query string with filled-in arguments and returns it 69 | const std::string BuildQueryString(); 70 | 71 | // returns a field name 72 | const std::string getFieldName(const unsigned int &field); 73 | // gets a string value from the given row and field 74 | const std::string getString(const unsigned int &row, const unsigned int &field); 75 | const std::string getString(const unsigned int &row, const std::string &field); 76 | // gets an int value from the given row and field 77 | int getInt(const unsigned int &row, const unsigned int &field); 78 | int getInt(const unsigned int &row, const std::string &field); 79 | // gets a double value from the given row and field 80 | double getDouble(const unsigned int &row, const unsigned int &field); 81 | double getDouble(const unsigned int &row, const std::string &field); 82 | // gets a time value from the given row and field 83 | time_t getTime(const unsigned int &row, const unsigned int &field); 84 | time_t getTime(const unsigned int &row, const std::string &field); 85 | 86 | // returns the result row count 87 | unsigned int GetResultRowCount(); 88 | unsigned int GetFieldCount(); 89 | 90 | 91 | private: 92 | typedef std::map TResultRow; 93 | MySQLConnection *m_sqlConn; 94 | int m_iResultRowCount; 95 | std::string m_sStatement; 96 | std::map m_mArgMap; 97 | std::map m_mResultMap; 98 | std::map m_mFieldMap; 99 | std::map m_mFieldStringToIntMap; 100 | 101 | }; 102 | 103 | #endif // MYSQLQUERY_H 104 | -------------------------------------------------------------------------------- /mysqlquery.cpp: -------------------------------------------------------------------------------- 1 | #include "mysqlquery.h" 2 | 3 | MySQLConnection::MySQLConnection() 4 | { 5 | m_bIsConnected = false; 6 | m_MySQLConn = NULL; 7 | m_sHostname = ""; 8 | m_sUsername = ""; 9 | m_sPassword = ""; 10 | m_wPort = 0; 11 | m_sSchemaName = ""; 12 | } 13 | 14 | MySQLConnection::~MySQLConnection() 15 | { 16 | if(m_MySQLConn != NULL) 17 | { 18 | std::clog << "Closing MySQL Connection" << std::endl; 19 | mysql_close(m_MySQLConn); 20 | } 21 | } 22 | 23 | bool MySQLConnection::Connect(const std::string &sHostname, const uint16_t &wPort, const std::string &sUsername, const std::string &sPassword, const std::string &sDB = NULL) 24 | { 25 | // If we're already connected, we should close the first connection 26 | Disconnect(); 27 | 28 | m_sHostname = sHostname; 29 | m_sUsername = sUsername; 30 | m_sPassword = sPassword; 31 | m_wPort = wPort; 32 | m_sSchemaName = sDB; 33 | m_bIsConnected = false; 34 | 35 | MYSQL *MySQLConnRet = NULL; 36 | m_MySQLConn = mysql_init(m_MySQLConn); 37 | 38 | std::clog << "Connection to " << m_sUsername << "@" << m_sHostname << ":" << wPort << "..." << std::endl; 39 | 40 | MySQLConnRet = mysql_real_connect(m_MySQLConn, m_sHostname.c_str(), m_sUsername.c_str(), m_sPassword.c_str(), m_sSchemaName.c_str(), m_wPort, NULL, 0); 41 | 42 | if(MySQLConnRet == NULL) 43 | { 44 | m_bIsConnected = false; 45 | std::cerr << "Connection failed: " << mysql_error(m_MySQLConn); 46 | } else { 47 | m_bIsConnected = true; 48 | std::clog << "Connected!" << std::endl; 49 | } 50 | 51 | return m_bIsConnected; 52 | } 53 | 54 | void MySQLConnection::Disconnect() 55 | { 56 | if(m_bIsConnected) 57 | { 58 | mysql_close(m_MySQLConn); 59 | std::clog << "Disconnected from MySQL DB!" << std::endl; 60 | } 61 | 62 | 63 | m_bIsConnected = false; 64 | 65 | } 66 | 67 | bool MySQLConnection::SelectDB(const std::string &sSchemaName) 68 | { 69 | if(!m_bIsConnected) 70 | { 71 | std::cerr << "Not connected to MySQL DB!" << std::endl; 72 | return false; 73 | } 74 | 75 | if(mysql_select_db(m_MySQLConn, sSchemaName.c_str()) != 0) 76 | { 77 | std::cerr << "Failed to select DB! Error: " << mysql_error(m_MySQLConn) << std::endl; 78 | return false; 79 | } else { 80 | m_sSchemaName = sSchemaName.c_str(); 81 | std::clog << "Selected database \"" << sSchemaName << "\"" << std::endl; 82 | return true; 83 | } 84 | } 85 | 86 | const std::string MySQLConnection::GetLastError() const 87 | { 88 | if(!m_bIsConnected) 89 | { 90 | std::cerr << "Not connected to MySQL DB!" << std::endl; 91 | return "Not connected"; 92 | } 93 | 94 | return (char*)mysql_error(m_MySQLConn); 95 | } 96 | 97 | MYSQL *MySQLConnection::getConn() 98 | { 99 | return m_MySQLConn; 100 | } 101 | 102 | bool MySQLConnection::IsConnected() 103 | { 104 | return m_bIsConnected; 105 | } 106 | 107 | const std::string MySQLConnection::EscapeString(const std::string &value) const 108 | { 109 | if(!m_bIsConnected) 110 | { 111 | std::cerr << "Not connected to MySQL DB!" << std::endl; 112 | return ""; 113 | } 114 | 115 | char *cValue = new char[(value.length()*2)+1]; 116 | mysql_real_escape_string(m_MySQLConn, cValue, value.c_str(), value.length()); 117 | 118 | std::string sRet = cValue; 119 | delete [] cValue; 120 | 121 | return sRet; 122 | } 123 | 124 | MySQLQuery::MySQLQuery(MySQLConnection *mConn, const std::string &sStatement) 125 | { 126 | m_sqlConn = mConn; 127 | m_sStatement = sStatement; 128 | m_iResultRowCount = 0; 129 | 130 | int argCount = std::count(m_sStatement.begin(), m_sStatement.end(), '?'); 131 | for(int i = 1; i <= argCount; i++) 132 | { 133 | m_mArgMap.insert(std::pair(i, "")); 134 | } 135 | } 136 | 137 | bool MySQLQuery::setString(const unsigned int &idx, const std::string &value) 138 | { 139 | 140 | if(idx > m_mArgMap.size()) 141 | { 142 | std::cerr << "Index exceeds total arg count in statement" << std::endl; 143 | return false; 144 | } 145 | 146 | std::stringstream ss; 147 | std::string escapedValue = m_sqlConn->EscapeString(value); 148 | ss << "\"" << escapedValue << "\""; 149 | m_mArgMap[idx] = ss.str(); 150 | 151 | return true; 152 | } 153 | 154 | bool MySQLQuery::setInt(const unsigned int &idx, const int &value) 155 | { 156 | if(idx > m_mArgMap.size()) 157 | { 158 | std::cerr << "Index exceeds total arg count in statement" << std::endl; 159 | return false; 160 | } 161 | 162 | std::stringstream ss; 163 | ss << value; 164 | m_mArgMap[idx] = ss.str(); 165 | 166 | return true; 167 | } 168 | 169 | bool MySQLQuery::setDouble(const unsigned int &idx, const double &value) 170 | { 171 | if(idx > m_mArgMap.size()) 172 | { 173 | std::cerr << "Index exceeds total arg count in statement" << std::endl; 174 | return false; 175 | } 176 | 177 | std::stringstream ss; 178 | ss << value; 179 | m_mArgMap[idx] = ss.str(); 180 | 181 | return true; 182 | } 183 | 184 | bool MySQLQuery::setTime(const unsigned int &idx, const time_t &value) 185 | { 186 | if(idx > m_mArgMap.size()) 187 | { 188 | std::cerr << "Index exceeds total arg count in statement" << std::endl; 189 | return false; 190 | } 191 | 192 | std::stringstream ss; 193 | ss << value; 194 | m_mArgMap[idx] = ss.str(); 195 | 196 | return true; 197 | } 198 | 199 | bool MySQLQuery::setNull(const unsigned int &idx) 200 | { 201 | if(idx > m_mArgMap.size()) 202 | { 203 | std::cerr << "Index exceeds total arg count in statement" << std::endl; 204 | return false; 205 | } 206 | 207 | m_mArgMap[idx] = "NULL"; 208 | return true; 209 | } 210 | 211 | const std::string MySQLQuery::getFieldName(const unsigned int &field) 212 | { 213 | if(field < 1) 214 | { 215 | std::cerr << "The field index has to be over 1!" << std::endl; 216 | return NULL; 217 | } else if(m_mFieldMap.size() < field){ 218 | std::cerr << "There are only " << m_mFieldMap.size() << " fields available!" << std::endl; 219 | return NULL; 220 | } 221 | 222 | std::string sFieldName = m_mFieldMap[field]; 223 | return sFieldName; 224 | } 225 | 226 | const std::string MySQLQuery::getString(const unsigned int &row, const unsigned int &field) 227 | { 228 | if(GetResultRowCount() < 1) 229 | { 230 | std::cerr << "The query didn't return any rows!" << std::endl; 231 | return NULL; 232 | } else if(GetResultRowCount() < row) 233 | { 234 | std::cerr << "There are only " << GetResultRowCount() << " rows available!" << std::endl; 235 | return NULL; 236 | } else if(row < 1) 237 | { 238 | std::cerr << "The selected row has to be > 1" << std::endl; 239 | return NULL; 240 | } 241 | 242 | TResultRow rSelectedRow; 243 | rSelectedRow = m_mResultMap[row-1]; 244 | 245 | std::string sValue = rSelectedRow[field]; 246 | 247 | return sValue; 248 | } 249 | 250 | const std::string MySQLQuery::getString(const unsigned int &row, const std::string &field) 251 | { 252 | if(GetResultRowCount() < 1) 253 | { 254 | std::cerr << "The query didn't return any rows!" << std::endl; 255 | return ""; 256 | } else if(GetResultRowCount() < row) 257 | { 258 | std::cerr << "There are only " << GetResultRowCount() << " rows available!" << std::endl; 259 | return ""; 260 | } else if(row < 1) 261 | { 262 | std::cerr << "The selected row has to be > 1" << std::endl; 263 | return ""; 264 | } 265 | 266 | TResultRow rSelectedRow; 267 | rSelectedRow = m_mResultMap[row-1]; 268 | 269 | int iFieldID = m_mFieldStringToIntMap[field]; 270 | std::string sValue = rSelectedRow[iFieldID]; 271 | 272 | return sValue; 273 | } 274 | 275 | int MySQLQuery::getInt(const unsigned int &row, const unsigned int &field) 276 | { 277 | if(GetResultRowCount() < 1) 278 | { 279 | std::cerr << "The query didn't return any rows!" << std::endl; 280 | return -1; 281 | } else if(GetResultRowCount() < row) 282 | { 283 | std::cerr << "There are only " << GetResultRowCount() << " rows available!" << std::endl; 284 | return -1; 285 | } else if(row < 1) 286 | { 287 | std::cerr << "The selected row has to be > 1" << std::endl; 288 | return -1; 289 | } 290 | 291 | TResultRow rSelectedRow; 292 | rSelectedRow = m_mResultMap[row-1]; 293 | 294 | int iValue = atoi(rSelectedRow[field].c_str()); 295 | 296 | return iValue; 297 | } 298 | 299 | int MySQLQuery::getInt(const unsigned int &row, const std::string &field) 300 | { 301 | if(GetResultRowCount() < 1) 302 | { 303 | std::cerr << "The query didn't return any rows!" << std::endl; 304 | return -1; 305 | } else if(GetResultRowCount() < row) 306 | { 307 | std::cerr << "There are only " << GetResultRowCount() << " rows available!" << std::endl; 308 | return -1; 309 | } else if(row < 1) 310 | { 311 | std::cerr << "The selected row has to be > 1" << std::endl; 312 | return -1; 313 | } 314 | 315 | TResultRow rSelectedRow; 316 | rSelectedRow = m_mResultMap[row-1]; 317 | 318 | int iFieldID = m_mFieldStringToIntMap[field]; 319 | int iValue = atoi(rSelectedRow[iFieldID].c_str()); 320 | 321 | return iValue; 322 | } 323 | 324 | double MySQLQuery::getDouble(const unsigned int &row, const unsigned int &field) 325 | { 326 | if(GetResultRowCount() < 1) 327 | { 328 | std::cerr << "The query didn't return any rows!" << std::endl; 329 | return -1.0; 330 | } else if(GetResultRowCount() < row) 331 | { 332 | std::cerr << "There are only " << GetResultRowCount() << " rows available!" << std::endl; 333 | return -1.0; 334 | } else if(row < 1) 335 | { 336 | std::cerr << "The selected row has to be > 1" << std::endl; 337 | return -1.0; 338 | } 339 | 340 | TResultRow rSelectedRow; 341 | rSelectedRow = m_mResultMap[row-1]; 342 | 343 | double dValue = atof(rSelectedRow[field].c_str()); 344 | 345 | return dValue; 346 | } 347 | 348 | double MySQLQuery::getDouble(const unsigned int &row, const std::string &field) 349 | { 350 | if(GetResultRowCount() < 1) 351 | { 352 | std::cerr << "The query didn't return any rows!" << std::endl; 353 | return -1.0; 354 | } else if(GetResultRowCount() < row) 355 | { 356 | std::cerr << "There are only " << GetResultRowCount() << " rows available!" << std::endl; 357 | return -1.0; 358 | } else if(row < 1) 359 | { 360 | std::cerr << "The selected row has to be > 1" << std::endl; 361 | return -1.0; 362 | } 363 | 364 | TResultRow rSelectedRow; 365 | rSelectedRow = m_mResultMap[row-1]; 366 | 367 | int iFieldID = m_mFieldStringToIntMap[field]; 368 | double dValue = atof(rSelectedRow[iFieldID].c_str()); 369 | 370 | return dValue; 371 | } 372 | 373 | time_t MySQLQuery::getTime(const unsigned int &row, const unsigned int &field) 374 | { 375 | if(GetResultRowCount() < 1) 376 | { 377 | std::cerr << "The query didn't return any rows!" << std::endl; 378 | return -1; 379 | } else if(GetResultRowCount() < row) 380 | { 381 | std::cerr << "There are only " << GetResultRowCount() << " rows available!" << std::endl; 382 | return -1; 383 | } else if(row < 1) 384 | { 385 | std::cerr << "The selected row has to be > 1" << std::endl; 386 | return -1; 387 | } 388 | 389 | TResultRow rSelectedRow; 390 | rSelectedRow = m_mResultMap[row-1]; 391 | 392 | time_t tValue = atoi(rSelectedRow[field].c_str()); 393 | 394 | return tValue; 395 | } 396 | 397 | time_t MySQLQuery::getTime(const unsigned int &row, const std::string &field) 398 | { 399 | if(GetResultRowCount() < 1) 400 | { 401 | std::cerr << "The query didn't return any rows!" << std::endl; 402 | return -1; 403 | } else if(GetResultRowCount() < row) 404 | { 405 | std::cerr << "There are only " << GetResultRowCount() << " rows available!" << std::endl; 406 | return -1; 407 | } else if(row < 1) 408 | { 409 | std::cerr << "The selected row has to be > 1" << std::endl; 410 | return -1; 411 | } 412 | 413 | TResultRow rSelectedRow; 414 | rSelectedRow = m_mResultMap[row-1]; 415 | 416 | int iFieldID = m_mFieldStringToIntMap[field]; 417 | time_t tValue = atoi(rSelectedRow[iFieldID].c_str()); 418 | 419 | return tValue; 420 | } 421 | 422 | 423 | unsigned int MySQLQuery::GetResultRowCount() 424 | { 425 | const int iRowCount = m_mResultMap.size(); 426 | return iRowCount; 427 | } 428 | 429 | unsigned int MySQLQuery::GetFieldCount() 430 | { 431 | const int iFieldCount = m_mFieldMap.size(); 432 | return iFieldCount; 433 | } 434 | 435 | const std::string MySQLQuery::BuildQueryString() 436 | { 437 | // replace each '?' with the corresponding value 438 | int iLastFoundPos = 0; 439 | std::string sPreparedStatement; 440 | sPreparedStatement = m_sStatement; 441 | for(unsigned int i = 1; i <= m_mArgMap.size(); i++) 442 | { 443 | iLastFoundPos = sPreparedStatement.find('?'); 444 | sPreparedStatement.replace(iLastFoundPos, 1, ""); 445 | sPreparedStatement.insert(iLastFoundPos, m_mArgMap[i]); 446 | } 447 | 448 | return sPreparedStatement; 449 | } 450 | 451 | bool MySQLQuery::ExecuteQuery() 452 | { 453 | std::string sStatement = BuildQueryString(); 454 | 455 | if(mysql_query(m_sqlConn->getConn(), sStatement.c_str())) 456 | { 457 | std::cerr << "MySQL Error: " << m_sqlConn->GetLastError() << std::endl; 458 | return false; 459 | } 460 | 461 | MYSQL_RES *result = mysql_store_result(m_sqlConn->getConn()); 462 | 463 | if(result == NULL) 464 | { 465 | std::cerr << "MySQL Error: " << m_sqlConn->GetLastError() << std::endl; 466 | return false; 467 | } 468 | 469 | 470 | int iNumFields = mysql_num_fields(result); 471 | MYSQL_ROW row; 472 | MYSQL_FIELD *field; 473 | 474 | // Get field names and store it in the map 475 | int i = 0; 476 | while((field = mysql_fetch_field(result))) 477 | { 478 | m_mFieldMap.insert(std::pair(i, field->name)); 479 | m_mFieldStringToIntMap.insert(std::pair(field->name, i)); 480 | i++; 481 | } 482 | 483 | // Get Rows 484 | i = 0; 485 | while((row = mysql_fetch_row(result))) 486 | { 487 | TResultRow resRow; 488 | for(int n = 0; n < iNumFields; n++) 489 | { 490 | resRow.insert(std::pair(n, row[n] ? row[n] : "NULL")); 491 | } 492 | 493 | m_mResultMap.insert(std::pair(i, resRow)); 494 | 495 | i++; 496 | } 497 | 498 | return true; 499 | } 500 | 501 | bool MySQLQuery::ExecuteUpdate() 502 | { 503 | std::string sStatement = BuildQueryString(); 504 | 505 | if(mysql_query(m_sqlConn->getConn(), sStatement.c_str())) 506 | { 507 | std::cerr << "MySQL Error: " << m_sqlConn->GetLastError() << std::endl; 508 | return false; 509 | } 510 | 511 | return true; 512 | } 513 | 514 | int MySQLQuery::ExecuteInsert() 515 | { 516 | std::string sStatement = BuildQueryString(); 517 | 518 | if(mysql_query(m_sqlConn->getConn(), sStatement.c_str())) 519 | { 520 | std::cerr << "MySQL Error: " << m_sqlConn->GetLastError() << std::endl; 521 | return 0; 522 | } 523 | 524 | int iLastInsertID = mysql_insert_id(m_sqlConn->getConn()); 525 | 526 | return iLastInsertID; 527 | } 528 | 529 | --------------------------------------------------------------------------------