//+------------------------------------------------------------------+ //| Warrior_EA | //| AnimateDread | //| | //+------------------------------------------------------------------+ #include "..\\System\\PrintVerbose.mqh" class CDatabaseConnectionManager { private: bool m_transactionActive; int m_databaseHandle; string m_dbPath; bool m_verboseMode; public: CDatabaseConnectionManager(bool verbose = false) { m_transactionActive = false; m_verboseMode = verbose; m_databaseHandle = INVALID_HANDLE; } bool Init(string path) { m_dbPath = path; return (true); } int GetDatabaseHandle() { return m_databaseHandle; } bool OpenDatabase() { if(m_databaseHandle != INVALID_HANDLE) { if(m_verboseMode) PrintVerbose("Database is already open."); return true; } int attempts = 0; while(attempts < 5) { m_databaseHandle = DatabaseOpen(m_dbPath, DATABASE_OPEN_COMMON | DATABASE_OPEN_CREATE | DATABASE_OPEN_READWRITE); if(m_databaseHandle != INVALID_HANDLE) { return true; } Print("Attempt " + IntegerToString(attempts + 1) + " failed to open database."); Sleep(1000); // Wait for a second before retrying attempts++; } Print("Database open failed after retries."); return false; } bool CloseDatabase() { if(m_databaseHandle != INVALID_HANDLE) { DatabaseClose(m_databaseHandle); m_databaseHandle = INVALID_HANDLE; } //--- MUST clear this with the handle. DatabaseClose() finalises whatever transaction was open, so //--- leaving the flag set left the object claiming an active transaction against a handle that no //--- longer exists: the next TransactionCommit()/Rollback() would sail past its own //--- !m_transactionActive early-return and call the API on INVALID_HANDLE. m_transactionActive = false; return(true); } //--- Every transaction call below validates the handle first. OpenDatabase() returns false after its //--- retries are exhausted, but a caller that ignores that return would otherwise pass INVALID_HANDLE //--- straight into the DatabaseTransaction* API, whose failure then reads as "the transaction failed" //--- rather than "there is no database" - two very different faults to chase in a log. bool TransactionBegin() { if(m_databaseHandle == INVALID_HANDLE) { Print("TransactionBegin: no open database (handle is INVALID_HANDLE) - did OpenDatabase() fail?"); return(false); } if(!DatabaseTransactionBegin(m_databaseHandle)) { Print("DatabaseTransactionBegin failed."); return(false); } else m_transactionActive = true; return(true); } bool TransactionCommit() { if(!m_transactionActive) return(true); if(m_databaseHandle == INVALID_HANDLE) { Print("TransactionCommit: database handle is INVALID_HANDLE - dropping the pending transaction."); m_transactionActive = false; return(false); } if(!DatabaseTransactionCommit(m_databaseHandle)) { Print("DatabaseTransactionCommit failed. Reverting changes..."); TransactionRollback(); m_transactionActive = false; return(false); } m_transactionActive = false; return(true); } bool TransactionRollback() { if(!m_transactionActive) return(true); if(m_databaseHandle == INVALID_HANDLE) { Print("TransactionRollback: database handle is INVALID_HANDLE - dropping the pending transaction."); m_transactionActive = false; return(false); } if(!DatabaseTransactionRollback(m_databaseHandle)) { Print("DatabaseTransactionRollback failed."); return(false); } m_transactionActive = false; return(true); } }; //+------------------------------------------------------------------+