Here is how I implement things, feel free to ask me any questions:
#include "SQLManager.hpp"
#include "sqlite3.h"
#include "cocos2d.h"
SQLManager* SQLManager::pinstance = 0;
SQLManager::SQLManager() {}
SQLManager* SQLManager::Instance()
{
if (pinstance == 0)
{
pinstance = new SQLManager;
pinstance->initInstance();
}
return pinstance;
}
void SQLManager::initInstance()
{
if (connect())
{
if (isDatabasePopulated())
{
// we have a valid database, but is it the latest version?
if (upgradeDatabase())
{
_bDatabaseReady = true;
}
else
{
std::cout << "The database failed to upgrade" << std::endl;
}
}
else
{
if (createDatabaseContents())
{
_bDatabaseReady = true;
}
else
{
std::cout << "We cannot create the database contents" << std::endl;
}
}
}
else
{
std::cout << "We cannot connect to database" << std::endl;
}
}
bool SQLManager::connect()
{
bool _bConnect = false;
_pdb = NULL;
_dbPath = cocos2d::FileUtils::getInstance()->getWritablePath() + _dbFile;
int result = sqlite3_open(_dbPath.c_str(), &_pdb);
if(result == SQLITE_OK)
{
//std::cout << "open database successfull!" << std::endl;
_bConnect = true;
}
return _bConnect;
}
bool SQLManager::isDatabasePopulated()
{
bool _bPopulated = false;
sqlite3_stmt *statement;
std::string _sql = "SELECT count(*) FROM (SELECT * FROM sqlite_master UNION ALL SELECT * FROM sqlite_temp_master) WHERE type='table' AND name='" +
std::string("Master") +
std::string("' ORDER BY name LIMIT 1;");
//std::cout << "sql: " << _sql << std::endl;
if(sqlite3_prepare_v2(_pdb, _sql.c_str(), -1, &statement, 0) == SQLITE_OK)
{
int cols = sqlite3_column_count(statement);
int result = 0;
while(true)
{
result = sqlite3_step(statement);
if(result == SQLITE_ROW)
{
for(int col = 0; col < cols; col++)
{
std::string s = (char*)sqlite3_column_text(statement, col);
//std::cout << "s: " << s << std::endl;
int result = std::stoi(s);
if(result == 1) // table exists, 0 if it doesn't exist
{
//std::cout << "We have AppMaster table" << std::endl;
_bPopulated = true;
}
else
{
std::cout << "We dont have APPMaster table" << std::endl;
}
}
}
else
{
break;
}
}
sqlite3_finalize(statement);
}
return _bPopulated;
}
bool SQLManager::createDatabaseContents()
{
bool _bMainTableCreatedOK = createMainTable();
if (_bMainTableCreatedOK)
{
return true;
}
else
{
return false;
}
}
bool SQLManager::createMainTable()
{
bool _bError = false;
bool _check = false;
int result = 0;
std::string _sql;
const std::vector<std::string> AppDBMasterTableID = {"HighScore", "HighTime",
"CurrentScore", "CurrentTime", "CurrentVersion", "VersionType"};
//std::cout << "Creating DB Master Table" << std::endl;
_sql = "create table " +
std::string("Master") +
std::string(" (_id TEXT PRIMARY KEY, _value INT);");
//std::cout << "sql: " << _sql << std::endl;
result = sqlite3_exec(_pdb, _sql.c_str(), NULL, NULL, NULL);
if(result == SQLITE_OK)
{
char buffer[300];
std::vector<int> AppDBMasterTableValue = {0, 0, 0, 0, _dbVersion};
for (unsigned i = 0; i < AppDBMasterTableID.size(); i++)
{
_sql = "INSERT INTO " +
std::string("Master") +
std::string(" VALUES ('%s', '%i')");
#ifdef _PRO_VERSION_
_dbVersionType = 0;
#endif
#ifdef _FREE_VERSION_
_dbVersionType = 1;
#endif
#ifdef _LITE_VERSION_
_dbVersionType = 2;
#endif
AppDBMasterTableValue.push_back(_dbVersionType);
sprintf(buffer, _sql.c_str(),
AppDBMasterTableID.at(i).c_str(),
AppDBMasterTableValue.at(i));
result = sqlite3_exec(_pdb, buffer, NULL, NULL, NULL);
//if(result == SQLITE_OK)
//{
// std::cout << "Insert to DB Master Table complete" << std::endl;
//}
//else
//{
// std::cout << "Inserts to DB Master Table failed" << std::endl;
//}
}
if (!_bError) // there were no errors
{
_check = true;
}
}
return _check;
}
bool SQLManager::upgradeDatabase()
{
int _version = getKeyByID("CurrentVersion", "_value");
if(_version == 1) // user has 1 -> upgrade to 13
{
if (upgradeTo13())
{
return true;
}
}
else
{
// assume they are up to date
return true;
}
}
bool SQLManager::upgradeTo13()
{
// for v1.3, we need to add the VersionType key, value pair.
int result = 0;
std::string _sql;
char buffer[300];
#ifdef _PRO_VERSION_
_dbVersionType = 0;
#endif
#ifdef _FREE_VERSION_
_dbVersionType = 1;
#endif
#ifdef _LITE_VERSION_
_dbVersionType = 2;
#endif
_sql = "INSERT INTO " +
std::string("Master") +
std::string(" VALUES ('%s', '%i')");
sprintf(buffer, _sql.c_str(),
"VersionType",
_dbVersionType);
result = sqlite3_exec(_pdb, buffer, NULL, NULL, NULL);
updateKey("CurrentVersion", 13);
return true;
}
int SQLManager::executeSelectQueryReturnSingleInt(const std::string& _sql)
{
sqlite3_stmt* statement;
if (sqlite3_prepare_v2(Instance()->getDatabase(), _sql.c_str(), -1, &statement, 0) == SQLITE_OK)
{
int cols = sqlite3_column_count(statement);
int result = 0;
while(true)
{
result = sqlite3_step(statement);
if(result == SQLITE_ROW)
{
for(int col = 0; col < cols; col++)
{
std::string s = (char*)sqlite3_column_text(statement, col);
//std::cout << "s: " << s << std::endl;
return std::stoi(s);
}
}
else
{
break;
}
}
}
return -1;
}
int SQLManager::getKeyByID(const std::string& _key, const std::string& _value)
{
std::string _sql = "SELECT " +
std::string(_value.c_str()) +
std::string(" FROM ") +
std::string("Master") +
std::string(" WHERE _id='") +
std::string(_key.c_str()) +
std::string("' LIMIT 1;");
//std::cout << "sql: " << _sql << std::endl;
int result = executeSelectQueryReturnSingleInt(_sql);
if (result == -1)
{
return 0;
}
else
{
return result;
}
}
std::string SQLManager::getSQLToCheckCounts(const std::string& _tableName)
{
return std::string("SELECT Count(*) FROM ") + _tableName + std::string(";");
}
void SQLManager::updateKey(const std::string& _key, const int& _value)
{
// UPDATE Books SET Author='Lev Nikolayevich Tolstoy' WHERE Id=1;
std::string _sql = "UPDATE " +
std::string("Master") +
std::string(" SET _value") +
std::string("=") +
std::to_string(_value) +
std::string(" WHERE _id='") +
std::string(_key.c_str()) +
std::string("';");
//std::cout << "sql: " << _sql << std::endl;
int result = sqlite3_exec(Instance()->getDatabase(), _sql.c_str(), NULL, NULL, NULL);
if (result == SQLITE_OK)
{
//std::cout << (std::string("update to Master: ") + std::string(_key.c_str()) + std::string(" successful")) << std::endl;
}
else
{
std::cout << (std::string("update to Master: ") + std::string(_key.c_str()) + std::string(" Failed")) << std::endl;
}
}