Tidy up database class files

This commit is contained in:
Vinnie Falco
2013-06-21 07:18:21 -07:00
parent 30213d24fa
commit 8a6d53ac64
9 changed files with 55 additions and 52 deletions

View File

@@ -1,5 +1,3 @@
// VFALCO TODO Rename the protobuf namespace from ripple to 'wire' or something
//
package protocol;
enum MessageType

View File

@@ -0,0 +1,194 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
Database::Database (const char* host, const char* user, const char* pass) : mNumCol (0)
{
mDBPass = pass;
mHost = host;
mUser = user;
}
Database::~Database ()
{
}
bool Database::getNull (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getNull (index);
}
return true;
}
char* Database::getStr (const char* colName, std::string& retStr)
{
int index;
if (getColNumber (colName, &index))
{
return getStr (index, retStr);
}
return NULL;
}
int32 Database::getInt (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getInt (index);
}
return 0;
}
float Database::getFloat (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getFloat (index);
}
return 0;
}
bool Database::getBool (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getBool (index);
}
return 0;
}
int Database::getBinary (const char* colName, unsigned char* buf, int maxSize)
{
int index;
if (getColNumber (colName, &index))
{
return (getBinary (index, buf, maxSize));
}
return (0);
}
Blob Database::getBinary (const std::string& strColName)
{
int index;
if (getColNumber (strColName.c_str (), &index))
{
return getBinary (index);
}
return Blob ();
}
std::string Database::getStrBinary (const std::string& strColName)
{
// YYY Could eliminate a copy if getStrBinary was a template.
return strCopy (getBinary (strColName.c_str ()));
}
uint64 Database::getBigInt (const char* colName)
{
int index;
if (getColNumber (colName, &index))
{
return getBigInt (index);
}
return 0;
}
// returns false if can't find col
bool Database::getColNumber (const char* colName, int* retIndex)
{
for (unsigned int n = 0; n < mColNameTable.size (); n++)
{
if (strcmp (colName, mColNameTable[n].c_str ()) == 0)
{
*retIndex = n;
return (true);
}
}
return false;
}
#if 0
int Database::getSingleDBValueInt (const char* sql)
{
int ret;
if ( executeSQL (sql) && startIterRows ()
{
ret = getInt (0);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif
#if 0
float Database::getSingleDBValueFloat (const char* sql)
{
float ret;
if (executeSQL (sql) && startIterRows () && getNextRow ())
{
ret = getFloat (0);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif
#if 0
char* Database::getSingleDBValueStr (const char* sql, std::string& retStr)
{
char* ret;
if (executeSQL (sql) && startIterRows ())
{
ret = getStr (0, retStr);
endIterRows ();
}
else
{
//theUI->statusMsg("ERROR with database: %s",sql);
ret = 0;
}
return (ret);
}
#endif
// vim:ts=4

View File

@@ -0,0 +1,116 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_DATABASE_RIPPLEHEADER
#define RIPPLE_DATABASE_RIPPLEHEADER
// VFALCO Get rid of these macros
//
#define SQL_FOREACH(_db, _strQuery) \
if ((_db)->executeSQL(_strQuery)) \
for (bool _bMore = (_db)->startIterRows(); _bMore; _bMore = (_db)->getNextRow())
#define SQL_EXISTS(_db, _strQuery) \
((_db)->executeSQL(_strQuery) && (_db)->startIterRows())
/*
this maintains the connection to the database
*/
class SqliteDatabase;
class JobQueue;
class Database
{
public:
// VFALCO TODO how are user and password even used?
//
Database (const char* host, const char* user, const char* pass);
virtual ~Database ();
virtual void connect () = 0;
virtual void disconnect () = 0;
std::string& getPass ()
{
return (mDBPass);
}
// returns true if the query went ok
virtual bool executeSQL (const char* sql, bool fail_okay = false) = 0;
bool executeSQL (std::string strSql, bool fail_okay = false)
{
return executeSQL (strSql.c_str (), fail_okay);
}
// returns false if there are no results
virtual bool startIterRows (bool finalize = true) = 0;
virtual void endIterRows () = 0;
// call this after you executeSQL
// will return false if there are no more rows
virtual bool getNextRow (bool finalize = true) = 0;
// get Data from the current row
bool getNull (const char* colName);
char* getStr (const char* colName, std::string& retStr);
std::string getStrBinary (const std::string& strColName);
int32 getInt (const char* colName);
float getFloat (const char* colName);
bool getBool (const char* colName);
// returns amount stored in buf
int getBinary (const char* colName, unsigned char* buf, int maxSize);
Blob getBinary (const std::string& strColName);
uint64 getBigInt (const char* colName);
virtual bool getNull (int colIndex) = 0;
virtual char* getStr (int colIndex, std::string& retStr) = 0;
virtual int32 getInt (int colIndex) = 0;
virtual float getFloat (int colIndex) = 0;
virtual bool getBool (int colIndex) = 0;
virtual int getBinary (int colIndex, unsigned char* buf, int maxSize) = 0;
virtual uint64 getBigInt (int colIndex) = 0;
virtual Blob getBinary (int colIndex) = 0;
// int getSingleDBValueInt(const char* sql);
// float getSingleDBValueFloat(const char* sql);
// char* getSingleDBValueStr(const char* sql, std::string& retStr);
virtual bool setupCheckpointing (JobQueue*)
{
return false;
}
virtual SqliteDatabase* getSqliteDB ()
{
return NULL;
}
virtual int getKBUsedAll ()
{
return -1;
}
virtual int getKBUsedDB ()
{
return -1;
}
protected:
bool getColNumber (const char* colName, int* retIndex);
int mNumCol;
std::string mUser;
std::string mHost;
std::string mDBPass;
std::vector <std::string> mColNameTable;
};
#endif
// vim:ts=4

View File

@@ -0,0 +1,439 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
SETUP_LOG (SqliteDatabase)
//using namespace std;
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);
}
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;
}
// 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 < mColNameTable.size (); n++)
{
mColNameTable[n] = sqlite3_column_name (mCurrentStmt, n);
}
if (!mMoreRows && finalize)
endIterRows ();
return (mMoreRows);
}
void SqliteDatabase::endIterRows ()
{
sqlite3_finalize (mCurrentStmt);
mCurrentStmt = NULL;
}
// call this after you executeSQL
// will return false if there are no more rows
bool SqliteDatabase::getNextRow (bool finalize)
{
if (mMoreRows)
{
int rc = sqlite3_step (mCurrentStmt);
if (rc == SQLITE_ROW)
return (true);
assert ((rc != SQLITE_BUSY) && (rc != SQLITE_LOCKED));
CondLog ((rc != SQLITE_DONE), lsWARNING, SqliteDatabase) << "Rerror: " << mHost << ": " << rc;
}
if (finalize)
endIterRows ();
return false;
}
bool SqliteDatabase::getNull (int colIndex)
{
return (SQLITE_NULL == sqlite3_column_type (mCurrentStmt, colIndex));
}
char* SqliteDatabase::getStr (int colIndex, std::string& retStr)
{
const char* text = reinterpret_cast<const char*> (sqlite3_column_text (mCurrentStmt, colIndex));
retStr = (text == NULL) ? "" : text;
return const_cast<char*> (retStr.c_str ());
}
int32 SqliteDatabase::getInt (int colIndex)
{
return (sqlite3_column_int (mCurrentStmt, colIndex));
}
float SqliteDatabase::getFloat (int colIndex)
{
return (static_cast <float> (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 < maxSize) maxSize = size;
memcpy (buf, blob, maxSize);
return (size);
}
Blob SqliteDatabase::getBinary (int colIndex)
{
const unsigned char* blob = reinterpret_cast<const unsigned char*> (sqlite3_column_blob (mCurrentStmt, colIndex));
size_t iSize = sqlite3_column_bytes (mCurrentStmt, colIndex);
Blob 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<int> (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<SqliteDatabase*> (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;
}
}
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, Blob const& 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<sqlite3_int64> (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);
}
Blob SqliteStatement::getBlob (int column)
{
int size = sqlite3_column_bytes (statement, column);
Blob ret (size);
memcpy (& (ret.front ()), sqlite3_column_blob (statement, column), size);
return ret;
}
std::string SqliteStatement::getString (int column)
{
return reinterpret_cast<const char*> (sqlite3_column_text (statement, column));
}
const char* SqliteStatement::peekString (int column)
{
return reinterpret_cast<const char*> (sqlite3_column_text (statement, column));
}
uint32 SqliteStatement::getUInt32 (int column)
{
return static_cast<uint32> (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

View File

@@ -0,0 +1,128 @@
//------------------------------------------------------------------------------
/*
Copyright (c) 2011-2013, OpenCoin, Inc.
*/
//==============================================================================
#ifndef RIPPLE_SQLITEDATABASE_RIPPLEHEADER
#define RIPPLE_SQLITEDATABASE_RIPPLEHEADER
struct sqlite3;
struct sqlite3_stmt;
class SqliteDatabase : public Database
{
public:
explicit SqliteDatabase (char const* host);
void connect ();
void disconnect ();
// returns true if the query went ok
bool executeSQL (const char* sql, bool fail_okay);
// tells you how many rows were changed by an update or insert
int getNumRowsAffected ();
// returns false if there are no results
bool startIterRows (bool finalize);
void endIterRows ();
// call this after you executeSQL
// will return false if there are no more rows
bool getNextRow (bool finalize);
bool getNull (int colIndex);
char* getStr (int colIndex, std::string& retStr);
int32 getInt (int colIndex);
float getFloat (int colIndex);
bool getBool (int colIndex);
// returns amount stored in buf
int getBinary (int colIndex, unsigned char* buf, int maxSize);
Blob getBinary (int colIndex);
uint64 getBigInt (int colIndex);
sqlite3* peekConnection ()
{
return mConnection;
}
sqlite3* getAuxConnection ();
virtual bool setupCheckpointing (JobQueue*);
virtual SqliteDatabase* getSqliteDB ()
{
return this;
}
void runWal ();
void doHook (const char* db, int walSize);
int getKBUsedDB ();
int getKBUsedAll ();
private:
sqlite3* mConnection;
// VFALCO TODO Why do we need an "aux" connection? Should just use a second SqliteDatabase object.
sqlite3* mAuxConnection;
sqlite3_stmt* mCurrentStmt;
bool mMoreRows;
boost::mutex walMutex;
JobQueue* mWalQ;
bool walRunning;
};
class SqliteStatement
{
private:
SqliteStatement (const SqliteStatement&); // no implementation
SqliteStatement& operator= (const SqliteStatement&); // no implementation
protected:
sqlite3_stmt* statement;
public:
// VFALCO TODO This is quite a convoluted interface. A mysterious "aux" connection?
// Why not just have two SqliteDatabase objects?
//
SqliteStatement (SqliteDatabase* db, const char* statement, bool aux = false);
SqliteStatement (SqliteDatabase* db, const std::string& statement, bool aux = false);
~SqliteStatement ();
sqlite3_stmt* peekStatement ();
// positions start at 1
int bind (int position, const void* data, int length);
int bindStatic (int position, const void* data, int length);
int bindStatic (int position, Blob const& value);
int bind (int position, const std::string& value);
int bindStatic (int position, const std::string& value);
int bind (int position, uint32 value);
int bind (int position);
// columns start at 0
int size (int column);
const void* peekBlob (int column);
Blob getBlob (int column);
std::string getString (int column);
const char* peekString (int column);
uint32 getUInt32 (int column);
int64 getInt64 (int column);
int step ();
int reset ();
// translate return values of step and reset
bool isOk (int);
bool isDone (int);
bool isRow (int);
bool isError (int);
std::string getError (int);
};
#endif
// vim:ts=4