00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include "sqlitedataprovider.h"
00022
00023 #include <stdexcept>
00024
00025 #include "dalexcept.h"
00026
00027 #include "../utils/logger.h"
00028
00029 namespace dal
00030 {
00031
00032
00033 const std::string SqLiteDataProvider::CFGPARAM_SQLITE_DB = "sqlite_database";
00034 const std::string SqLiteDataProvider::CFGPARAM_SQLITE_DB_DEF = "tmw.db";
00035
00036
00040 SqLiteDataProvider::SqLiteDataProvider(void)
00041 throw()
00042 : mDb(0)
00043 {
00044
00045 }
00046
00047
00051 SqLiteDataProvider::~SqLiteDataProvider(void)
00052 throw()
00053 {
00054 try {
00055
00056
00057
00058 if (mIsConnected) {
00059 disconnect();
00060 }
00061 }
00062 catch (...) {
00063
00064 }
00065 }
00066
00067
00071 DbBackends
00072 SqLiteDataProvider::getDbBackend(void) const
00073 throw()
00074 {
00075 return DB_BKEND_SQLITE;
00076 }
00077
00078
00082 void
00083 SqLiteDataProvider::connect()
00084 {
00085
00086 const std::string dbName
00087 = Configuration::getValue(CFGPARAM_SQLITE_DB, CFGPARAM_SQLITE_DB_DEF);
00088
00089 LOG_INFO("Trying to connect with SQLite database file '"
00090 << dbName << "'");
00091
00092
00093
00094 if (sqlite3_open(dbName.c_str(), &mDb) != SQLITE_OK) {
00095
00096
00097 std::string msg(sqlite3_errmsg(mDb));
00098
00099
00100
00101 sqlite3_close(mDb);
00102
00103
00104
00105
00106
00107 throw DbConnectionFailure(msg);
00108 }
00109
00110
00111 mDbName = dbName;
00112
00113 mIsConnected = true;
00114 LOG_INFO("Connection to database successful.");
00115 }
00116
00117
00121 const RecordSet&
00122 SqLiteDataProvider::execSql(const std::string& sql,
00123 const bool refresh)
00124 {
00125 if (!mIsConnected) {
00126 throw std::runtime_error("not connected to database");
00127 }
00128
00129 LOG_DEBUG("Performing SQL query: "<<sql);
00130
00131
00132
00133
00134 if (refresh || (sql != mSql)) {
00135 char** result;
00136 int nRows;
00137 int nCols;
00138 char* errMsg;
00139
00140 mRecordSet.clear();
00141
00142 int errCode = sqlite3_get_table(
00143 mDb,
00144 sql.c_str(),
00145 &result,
00146 &nRows,
00147 &nCols,
00148 &errMsg
00149 );
00150
00151 if (errCode != SQLITE_OK) {
00152 std::string msg(sqlite3_errmsg(mDb));
00153
00154 LOG_ERROR("Error in SQL: " << sql << "\n" << msg);
00155
00156
00157 sqlite3_free_table(result);
00158 sqlite3_free(errMsg);
00159
00160 throw DbSqlQueryExecFailure(msg);
00161 }
00162
00163
00164 Row fieldNames;
00165 for(int col = 0; col < nCols; ++col) {
00166 fieldNames.push_back(result[col]);
00167 }
00168 mRecordSet.setColumnHeaders(fieldNames);
00169
00170
00171 for (int row = 0; row < nRows; ++row) {
00172 Row r;
00173
00174 for(int col = 0; col < nCols; ++col) {
00175 r.push_back(result[nCols + (row * nCols) + col]);
00176
00177 }
00178
00179 mRecordSet.add(r);
00180 }
00181
00182
00183 sqlite3_free_table(result);
00184 sqlite3_free(errMsg);
00185 }
00186
00187 return mRecordSet;
00188 }
00189
00190
00194 void
00195 SqLiteDataProvider::disconnect(void)
00196 {
00197 if (!isConnected()) {
00198 return;
00199 }
00200
00201
00202
00203 if (sqlite3_close(mDb) != SQLITE_OK) {
00204 throw DbDisconnectionFailure(sqlite3_errmsg(mDb));
00205 }
00206
00207 mDb = 0;
00208 mIsConnected = false;
00209 }
00210
00211 void
00212 SqLiteDataProvider::beginTransaction(void)
00213 throw (std::runtime_error)
00214 {
00215 if (!mIsConnected)
00216 {
00217 const std::string error = "Trying to begin a transaction while not "
00218 "connected to the database!";
00219 LOG_ERROR(error);
00220 throw std::runtime_error(error);
00221 }
00222
00223 if (inTransaction())
00224 {
00225 const std::string error = "Trying to begin a transaction while anoter "
00226 "one is still open!";
00227 LOG_ERROR(error);
00228 throw std::runtime_error(error);
00229 }
00230
00231
00232 try
00233 {
00234 execSql("BEGIN TRANSACTION;");
00235 LOG_DEBUG("SQL: started transaction");
00236 }
00237 catch (const DbSqlQueryExecFailure &e)
00238 {
00239 std::ostringstream error;
00240 error << "SQL ERROR while trying to start a transaction: " << e.what();
00241 LOG_ERROR(error);
00242 throw std::runtime_error(error.str());
00243 }
00244 }
00245
00246 void
00247 SqLiteDataProvider::commitTransaction(void)
00248 throw (std::runtime_error)
00249 {
00250 if (!mIsConnected)
00251 {
00252 const std::string error = "Trying to commit a transaction while not "
00253 "connected to the database!";
00254 LOG_ERROR(error);
00255 throw std::runtime_error(error);
00256 }
00257
00258 if (!inTransaction())
00259 {
00260 const std::string error = "Trying to commit a transaction while no "
00261 "one is open!";
00262 LOG_ERROR(error);
00263 throw std::runtime_error(error);
00264 }
00265
00266
00267 try
00268 {
00269 execSql("COMMIT TRANSACTION;");
00270 LOG_DEBUG("SQL: commited transaction");
00271 }
00272 catch (const DbSqlQueryExecFailure &e)
00273 {
00274 std::ostringstream error;
00275 error << "SQL ERROR while trying to commit a transaction: " << e.what();
00276 LOG_ERROR(error);
00277 throw std::runtime_error(error.str());
00278 }
00279 }
00280
00281 void
00282 SqLiteDataProvider::rollbackTransaction(void)
00283 throw (std::runtime_error)
00284 {
00285 if (!mIsConnected)
00286 {
00287 const std::string error = "Trying to rollback a transaction while not "
00288 "connected to the database!";
00289 LOG_ERROR(error);
00290 throw std::runtime_error(error);
00291 }
00292
00293 if (!inTransaction())
00294 {
00295 const std::string error = "Trying to rollback a transaction while no "
00296 "one is open!";
00297 LOG_ERROR(error);
00298 throw std::runtime_error(error);
00299 }
00300
00301
00302 try
00303 {
00304 execSql("ROLLBACK TRANSACTION;");
00305 LOG_DEBUG("SQL: transaction rolled back");
00306 }
00307 catch (const DbSqlQueryExecFailure &e)
00308 {
00309 std::ostringstream error;
00310 error << "SQL ERROR while trying to rollback a transaction: " << e.what();
00311 LOG_ERROR(error);
00312 throw std::runtime_error(error.str());
00313 }
00314 }
00315
00316 const unsigned int
00317 SqLiteDataProvider::getModifiedRows(void) const
00318 {
00319 if (!mIsConnected)
00320 {
00321 const std::string error = "Trying to getModifiedRows while not "
00322 "connected to the database!";
00323 LOG_ERROR(error);
00324 throw std::runtime_error(error);
00325 }
00326
00327 return (unsigned int)sqlite3_changes(mDb);
00328 }
00329
00330 const bool
00331 SqLiteDataProvider::inTransaction(void) const
00332 {
00333 if (!mIsConnected)
00334 {
00335 const std::string error = "not connected to the database!";
00336 LOG_ERROR(error);
00337 throw std::runtime_error(error);
00338 }
00339
00340
00341
00342
00343
00344 const int ret = sqlite3_get_autocommit(mDb);
00345 if (ret == 0)
00346 {
00347 return true;
00348 }
00349 else
00350 {
00351 return false;
00352 }
00353 }
00354
00355 const unsigned int
00356 SqLiteDataProvider::getLastId(void) const
00357 {
00358 if (!mIsConnected)
00359 {
00360 const std::string error = "not connected to the database!";
00361 LOG_ERROR(error);
00362 throw std::runtime_error(error);
00363 }
00364
00365
00366 const sqlite3_int64 lastId = sqlite3_last_insert_rowid(mDb);
00367 if (lastId > UINT_MAX)
00368 throw std::runtime_error("SqLiteDataProvider::getLastId exceeded INT_MAX");
00369
00370 return (unsigned int)lastId;
00371 }
00372
00373 }