#include "SqliteDatabase.h" #include "sqlite3.h" #include #include #include #include #include #include #include "../ripple/JobQueue.h" SETUP_LOG (SqliteDatabase) using namespace std; SqliteDatabase::SqliteDatabase(const char* host) : Database(host,"",""), mWalQ(NULL), walRunning(false) { mConnection = NULL; mAuxConnection = NULL; mCurrentStmt = NULL; } void SqliteDatabase::connect() { int rc = sqlite3_open(mHost.c_str(), &mConnection); if (rc) { WriteLog (lsFATAL, SqliteDatabase) << "Can't open " << mHost << " " << rc; sqlite3_close(mConnection); assert((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED)); } } sqlite3* SqliteDatabase::getAuxConnection() { boost::mutex::scoped_lock sl(walMutex); if (mAuxConnection == NULL) { int rc = sqlite3_open(mHost.c_str(), &mAuxConnection); if (rc) { WriteLog (lsFATAL, SqliteDatabase) << "Can't aux open " << mHost << " " << rc; assert((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED)); if (mAuxConnection != NULL) { sqlite3_close(mConnection); mAuxConnection = NULL; } } } return mAuxConnection; } void SqliteDatabase::disconnect() { sqlite3_finalize(mCurrentStmt); sqlite3_close(mConnection); if (mAuxConnection != NULL) sqlite3_close(mAuxConnection); } // returns true if the query went ok bool SqliteDatabase::executeSQL(const char* sql, bool fail_ok) { #ifdef DEBUG_HANGING_LOCKS assert(fail_ok || (mCurrentStmt == NULL)); #endif sqlite3_finalize(mCurrentStmt); int rc = sqlite3_prepare_v2(mConnection, sql, -1, &mCurrentStmt, NULL); if (SQLITE_OK != rc) { if (!fail_ok) { #ifdef DEBUG WriteLog (lsWARNING, SqliteDatabase) << "Perror:" << mHost << ": " << rc; WriteLog (lsWARNING, SqliteDatabase) << "Statement: " << sql; WriteLog (lsWARNING, SqliteDatabase) << "Error: " << sqlite3_errmsg(mConnection); #endif } endIterRows(); return false; } rc = sqlite3_step(mCurrentStmt); if (rc == SQLITE_ROW) { mMoreRows = true; } else if (rc == SQLITE_DONE) { endIterRows(); mMoreRows = false; } else { if ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED)) { WriteLog (lsFATAL, SqliteDatabase) << mHost << " returns error " << rc << ": " << sqlite3_errmsg(mConnection); assert(false); } mMoreRows = false; if (!fail_ok) { #ifdef DEBUG WriteLog (lsWARNING, SqliteDatabase) << "SQL Serror:" << mHost << ": " << rc; WriteLog (lsWARNING, SqliteDatabase) << "Statement: " << sql; WriteLog (lsWARNING, SqliteDatabase) << "Error: " << sqlite3_errmsg(mConnection); #endif } endIterRows(); return false; } return true; } // tells you how many rows were changed by an update or insert int SqliteDatabase::getNumRowsAffected() { // TODO: SqliteDatabase::getNumRowsAffected() return(0); } // VFALCO: TODO, This must be fixed!!! return value needs to be int64 // int SqliteDatabase::getLastInsertID() { return(sqlite3_last_insert_rowid(mConnection)); } // returns false if there are no results bool SqliteDatabase::startIterRows(bool finalize) { mColNameTable.clear(); mColNameTable.resize(sqlite3_column_count(mCurrentStmt)); for(unsigned n=0; n(sqlite3_column_text(mCurrentStmt, colIndex)); retStr = (text == NULL) ? "" : text; return const_cast(retStr.c_str()); } int32 SqliteDatabase::getInt(int colIndex) { return(sqlite3_column_int(mCurrentStmt, colIndex)); } float SqliteDatabase::getFloat(int colIndex) { return(static_cast (sqlite3_column_double(mCurrentStmt, colIndex))); } bool SqliteDatabase::getBool(int colIndex) { return(sqlite3_column_int(mCurrentStmt, colIndex) ? true : false); } int SqliteDatabase::getBinary(int colIndex,unsigned char* buf,int maxSize) { const void* blob=sqlite3_column_blob(mCurrentStmt, colIndex); int size=sqlite3_column_bytes(mCurrentStmt, colIndex); if(size SqliteDatabase::getBinary(int colIndex) { const unsigned char* blob = reinterpret_cast(sqlite3_column_blob(mCurrentStmt, colIndex)); size_t iSize = sqlite3_column_bytes(mCurrentStmt, colIndex); std::vector vucResult; vucResult.resize(iSize); std::copy(blob, blob+iSize, vucResult.begin()); return vucResult; } uint64 SqliteDatabase::getBigInt(int colIndex) { return(sqlite3_column_int64(mCurrentStmt, colIndex)); } int SqliteDatabase::getKBUsedAll() { return static_cast(sqlite3_memory_used() / 1024); } int SqliteDatabase::getKBUsedDB() { int cur = 0, hiw = 0; sqlite3_db_status(mConnection, SQLITE_DBSTATUS_CACHE_USED, &cur, &hiw, 0); return cur / 1024; } static int SqliteWALHook(void *s, sqlite3* dbCon, const char *dbName, int walSize) { (reinterpret_cast(s))->doHook(dbName, walSize); return SQLITE_OK; } bool SqliteDatabase::setupCheckpointing(JobQueue *q) { mWalQ = q; sqlite3_wal_hook(mConnection, SqliteWALHook, this); return true; } void SqliteDatabase::doHook(const char *db, int pages) { if (pages < 1000) return; { boost::mutex::scoped_lock sl(walMutex); if (walRunning) return; walRunning = true; } if (mWalQ) mWalQ->addJob(jtWAL, std::string("WAL:") + mHost, boost::bind(&SqliteDatabase::runWal, this)); else boost::thread(boost::bind(&SqliteDatabase::runWal, this)).detach(); } void SqliteDatabase::runWal() { int log = 0, ckpt = 0; int ret = sqlite3_wal_checkpoint_v2(mConnection, NULL, SQLITE_CHECKPOINT_PASSIVE, &log, &ckpt); if (ret != SQLITE_OK) { WriteLog ((ret == SQLITE_LOCKED) ? lsTRACE : lsWARNING, SqliteDatabase) << "WAL(" << sqlite3_db_filename(mConnection, "main") << "): error " << ret; } else WriteLog (lsTRACE, SqliteDatabase) << "WAL(" << sqlite3_db_filename(mConnection, "main") << "): frames=" << log << ", written=" << ckpt; { boost::mutex::scoped_lock sl(walMutex); walRunning = false; } } SqliteStatement::SqliteStatement(SqliteDatabase* db, const char *sql, bool aux) { assert(db); sqlite3* conn = aux ? db->getAuxConnection() : db->peekConnection(); int j = sqlite3_prepare_v2(conn, sql, strlen(sql) + 1, &statement, NULL); if (j != SQLITE_OK) throw j; } SqliteStatement::SqliteStatement(SqliteDatabase* db, const std::string& sql, bool aux) { assert(db); sqlite3* conn = aux ? db->getAuxConnection() : db->peekConnection(); int j = sqlite3_prepare_v2(conn, sql.c_str(), sql.size() + 1, &statement, NULL); if (j != SQLITE_OK) throw j; } SqliteStatement::~SqliteStatement() { sqlite3_finalize(statement); } sqlite3_stmt* SqliteStatement::peekStatement() { return statement; } int SqliteStatement::bind(int position, const void *data, int length) { return sqlite3_bind_blob(statement, position, data, length, SQLITE_TRANSIENT); } int SqliteStatement::bindStatic(int position, const void *data, int length) { return sqlite3_bind_blob(statement, position, data, length, SQLITE_STATIC); } int SqliteStatement::bindStatic(int position, const std::vector& value) { return sqlite3_bind_blob(statement, position, &value.front(), value.size(), SQLITE_STATIC); } int SqliteStatement::bind(int position, uint32 value) { return sqlite3_bind_int64(statement, position, static_cast(value)); } int SqliteStatement::bind(int position, const std::string& value) { return sqlite3_bind_text(statement, position, value.data(), value.size(), SQLITE_TRANSIENT); } int SqliteStatement::bindStatic(int position, const std::string& value) { return sqlite3_bind_text(statement, position, value.data(), value.size(), SQLITE_STATIC); } int SqliteStatement::bind(int position) { return sqlite3_bind_null(statement, position); } int SqliteStatement::size(int column) { return sqlite3_column_bytes(statement, column); } const void* SqliteStatement::peekBlob(int column) { return sqlite3_column_blob(statement, column); } std::vector SqliteStatement::getBlob(int column) { int size = sqlite3_column_bytes(statement, column); std::vector ret(size); memcpy(&(ret.front()), sqlite3_column_blob(statement, column), size); return ret; } std::string SqliteStatement::getString(int column) { return reinterpret_cast(sqlite3_column_text(statement, column)); } const char* SqliteStatement::peekString(int column) { return reinterpret_cast(sqlite3_column_text(statement, column)); } uint32 SqliteStatement::getUInt32(int column) { return static_cast(sqlite3_column_int64(statement, column)); } int64 SqliteStatement::getInt64(int column) { return sqlite3_column_int64(statement, column); } int SqliteStatement::step() { return sqlite3_step(statement); } int SqliteStatement::reset() { return sqlite3_reset(statement); } bool SqliteStatement::isOk(int j) { return j == SQLITE_OK; } bool SqliteStatement::isDone(int j) { return j == SQLITE_DONE; } bool SqliteStatement::isRow(int j) { return j == SQLITE_ROW; } bool SqliteStatement::isError(int j) { switch (j) { case SQLITE_OK: case SQLITE_ROW: case SQLITE_DONE: return true; default: return false; } } std::string SqliteStatement::getError(int j) { return sqlite3_errstr(j); } // vim:ts=4