diff --git a/src/cpp/ripple/Ledger.cpp b/src/cpp/ripple/Ledger.cpp index 0cb2f0b2a4..bc68f6350a 100644 --- a/src/cpp/ripple/Ledger.cpp +++ b/src/cpp/ripple/Ledger.cpp @@ -506,8 +506,62 @@ void Ledger::saveAcceptedLedger(bool fromConsensus, LoadEvent::pointer event) decPendingSaves(); } -Ledger::pointer Ledger::getSQL(const std::string& sql) +#ifndef NO_SQLITE3_PREPARE + +Ledger::pointer Ledger::loadByIndex(uint32 ledgerIndex) { + Database* db = theApp->getLedgerDB()->getDB(); + ScopedLock sl(theApp->getLedgerDB()->getDBLock()); + + static SqliteStatement pSt(db->getSqliteDB(), "SELECT " + "LedgerHash,PrevHash,AccountSetHash,TransSetHash,TotalCoins," + "ClosingTime,PrevClosingTime,CloseTimeRes,CloseFlags,LedgerSeq" + " from Ledgers WHERE LedgerSeq = ?;"); + + pSt.reset(); + pSt.bind(1, ledgerIndex); + return getSQL(&pSt); +} + +Ledger::pointer Ledger::loadByHash(const uint256& ledgerHash) +{ + Database* db = theApp->getLedgerDB()->getDB(); + ScopedLock sl(theApp->getLedgerDB()->getDBLock()); + + static SqliteStatement pSt(db->getSqliteDB(), "SELECT " + "LedgerHash,PrevHash,AccountSetHash,TransSetHash,TotalCoins," + "ClosingTime,PrevClosingTime,CloseTimeRes,CloseFlags,LedgerSeq" + " from Ledgers WHERE LedgerHash = ?;"); + + pSt.reset(); + pSt.bind(1, ledgerHash.GetHex()); + Ledger::pointer ret = getSQL(&pSt); + assert(!ret || (ret->getHash() == ledgerHash)); + return ret; +} + +#else + +Ledger::pointer Ledger::loadByIndex(uint32 ledgerIndex) +{ // This is a low-level function with no caching + std::string sql="SELECT * from Ledgers WHERE LedgerSeq='"; + sql.append(boost::lexical_cast(ledgerIndex)); + sql.append("';"); + return getSQL(sql); +} + +Ledger::pointer Ledger::loadByHash(const uint256& ledgerHash) +{ // This is a low-level function with no caching and only gets accepted ledgers + std::string sql="SELECT * from Ledgers WHERE LedgerHash='"; + sql.append(ledgerHash.GetHex()); + sql.append("';"); + return getSQL(sql); +} + +#endif + +Ledger::pointer Ledger::getSQL(const std::string& sql) +{ // only used with sqlite3 prepared statements not used uint256 ledgerHash, prevHash, accountHash, transHash; uint64 totCoins; uint32 closingTime, prevClosingTime, ledgerSeq; @@ -539,7 +593,59 @@ Ledger::pointer Ledger::getSQL(const std::string& sql) db->endIterRows(); } -// Log(lsTRACE) << "Constructing ledger " << ledgerSeq << " from SQL"; + // CAUTION: code below appears in two places + Ledger::pointer ret = boost::make_shared(prevHash, transHash, accountHash, totCoins, + closingTime, prevClosingTime, closeFlags, closeResolution, ledgerSeq); + ret->setClosed(); + if (theApp->getOPs().haveLedger(ledgerSeq)) + ret->setAccepted(); + if (ret->getHash() != ledgerHash) + { + if (sLog(lsERROR)) + { + Log(lsERROR) << "Failed on ledger"; + Json::Value p; + ret->addJson(p, LEDGER_JSON_FULL); + Log(lsERROR) << p; + } + assert(false); + return Ledger::pointer(); + } + cLog(lsTRACE) << "Loaded ledger: " << ledgerHash; + return ret; +} + +Ledger::pointer Ledger::getSQL(SqliteStatement *stmt) +{ + int iRet = stmt->step(); + if (stmt->isDone(iRet)) + return Ledger::pointer(); + + if (!stmt->isRow(iRet)) + { + cLog(lsINFO) << "Ledger not found: " << iRet << " = " << stmt->getError(iRet); + return Ledger::pointer(); + } + + uint256 ledgerHash, prevHash, accountHash, transHash; + uint64 totCoins; + uint32 closingTime, prevClosingTime, ledgerSeq; + int closeResolution; + unsigned closeFlags; + std::string hash; + + ledgerHash.SetHex(stmt->peekString(0), true); + prevHash.SetHex(stmt->peekString(1), true); + accountHash.SetHex(stmt->peekString(2), true); + transHash.SetHex(stmt->peekString(3), true); + totCoins = stmt->getInt64(4); + closingTime = stmt->getUInt32(5); + prevClosingTime = stmt->getUInt32(6); + closeResolution = stmt->getUInt32(7); + closeFlags = stmt->getUInt32(8); + ledgerSeq = stmt->getUInt32(9); + + // CAUTION: code below appears in two places Ledger::pointer ret = boost::make_shared(prevHash, transHash, accountHash, totCoins, closingTime, prevClosingTime, closeFlags, closeResolution, ledgerSeq); ret->setClosed(); @@ -641,22 +747,6 @@ bool Ledger::getHashesByIndex(uint32 ledgerIndex, uint256& ledgerHash, uint256& #endif } -Ledger::pointer Ledger::loadByIndex(uint32 ledgerIndex) -{ // This is a low-level function with no caching - std::string sql="SELECT * from Ledgers WHERE LedgerSeq='"; - sql.append(boost::lexical_cast(ledgerIndex)); - sql.append("';"); - return getSQL(sql); -} - -Ledger::pointer Ledger::loadByHash(const uint256& ledgerHash) -{ // This is a low-level function with no caching and only gets accepted ledgers - std::string sql="SELECT * from Ledgers WHERE LedgerHash='"; - sql.append(ledgerHash.GetHex()); - sql.append("';"); - return getSQL(sql); -} - Ledger::pointer Ledger::getLastFullLedger() { try diff --git a/src/cpp/ripple/Ledger.h b/src/cpp/ripple/Ledger.h index 71ede9357f..da67e0d119 100644 --- a/src/cpp/ripple/Ledger.h +++ b/src/cpp/ripple/Ledger.h @@ -41,6 +41,8 @@ enum LedgerStateParms DEFINE_INSTANCE(Ledger); +class SqliteStatement; + class Ledger : public boost::enable_shared_from_this, public IS_INSTANCE(Ledger) { // The basic Ledger structure, can be opened, closed, or synching friend class TransactionEngine; @@ -117,6 +119,7 @@ public: Ledger(Ledger& target, bool isMutable); // snapshot static Ledger::pointer getSQL(const std::string& sqlStatement); + static Ledger::pointer getSQL(SqliteStatement*); static Ledger::pointer getLastFullLedger(); static int getPendingSaves();