2025-05-30 16:35:54 +02:00 | | | //+------------------------------------------------------------------+
|
| | | //| 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;
|
| | | }
|
2026-08-01 11:27:28 -04:00 | | | //--- 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;
|
2025-05-30 16:35:54 +02:00 | | | return(true);
|
| | | }
|
2026-08-01 11:27:28 -04:00 | | | //--- 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.
|
2025-05-30 16:35:54 +02:00 | | | bool TransactionBegin()
|
| | | {
|
2026-08-01 11:27:28 -04:00 | | | if(m_databaseHandle == INVALID_HANDLE)
|
| | | {
|
| | | Print("TransactionBegin: no open database (handle is INVALID_HANDLE) - did OpenDatabase() fail?");
|
| | | return(false);
|
| | | }
|
2025-05-30 16:35:54 +02:00 | | | if(!DatabaseTransactionBegin(m_databaseHandle))
|
| | | {
|
| | | Print("DatabaseTransactionBegin failed.");
|
| | | return(false);
|
| | | }
|
| | | else
|
| | | m_transactionActive = true;
|
| | | return(true);
|
| | | }
|
| | | bool TransactionCommit()
|
| | | {
|
| | | if(!m_transactionActive)
|
| | | return(true);
|
2026-08-01 11:27:28 -04:00 | | | if(m_databaseHandle == INVALID_HANDLE)
|
| | | {
|
| | | Print("TransactionCommit: database handle is INVALID_HANDLE - dropping the pending transaction.");
|
| | | m_transactionActive = false;
|
| | | return(false);
|
| | | }
|
2025-05-30 16:35:54 +02:00 | | | 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);
|
2026-08-01 11:27:28 -04:00 | | | if(m_databaseHandle == INVALID_HANDLE)
|
| | | {
|
| | | Print("TransactionRollback: database handle is INVALID_HANDLE - dropping the pending transaction.");
|
| | | m_transactionActive = false;
|
| | | return(false);
|
| | | }
|
2025-05-30 16:35:54 +02:00 | | | if(!DatabaseTransactionRollback(m_databaseHandle))
|
| | | {
|
| | | Print("DatabaseTransactionRollback failed.");
|
| | | return(false);
|
| | | }
|
2026-07-26 12:12:14 -04:00 | | | m_transactionActive = false;
|
2025-05-30 16:35:54 +02:00 | | | return(true);
|
| | | }
|
| | | };
|
| | | //+------------------------------------------------------------------+
|