Skip to content

Commit

Permalink
Fixed CSV Serializer. EA class now fully exports SQLite databases.
Browse files Browse the repository at this point in the history
Usage: ```
  ea_params.Set(EA_PARAM_DATA_STORE, EA_DATA_STORE_ALL);
  ea_params.Set(EA_PARAM_DATA_EXPORT, EA_DATA_EXPORT_ALL);

  TaskEntry _task1(EA_ACTION_EXPORT_DATA, EA_COND_ON_NEW_HOUR);
  ea_params.SetTaskEntry(_task1);
```
  • Loading branch information
nseam committed Jul 16, 2021
1 parent 7af978a commit 3ee4114
Show file tree
Hide file tree
Showing 10 changed files with 289 additions and 183 deletions.
293 changes: 169 additions & 124 deletions Database.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -118,167 +118,212 @@ class Database {
/**
* Class constructor.
*/
Database(string _filename, unsigned int _flags = DATABASE_OPEN_CREATE) {
#ifdef __MQL5__
handle = DatabaseOpen(_filename, _flags);
#ifndef __MQL4__
Database(string _filename, unsigned int _flags = DATABASE_OPEN_CREATE){
#else
Database(string _filename, unsigned int _flags = 0) {
#endif
#ifndef __MQL4__
handle = DatabaseOpen(_filename, _flags);
#else
handle = -1;
SetUserError(ERR_USER_NOT_SUPPORTED);
#endif
}
}

/**
* Class deconstructor.
*/
~Database() {
#ifdef __MQL5__
DatabaseClose(handle);
/**
* Class deconstructor.
*/
~Database() {
#ifndef __MQL4__
DatabaseClose(handle);
#endif
}
}

/* Table methods */
/* Table methods */

/**
* Checks if table exists.
*/
bool TableExists(string _name) { return DatabaseTableExists(handle, _name); }
/**
* Checks if table exists.
*/
bool TableExists(string _name) {
#ifndef __MQL4__
return DatabaseTableExists(handle, _name);
#else
SetUserError(ERR_USER_NOT_SUPPORTED);
return false;
#endif
}

/**
* Creates table if not yet exist.
*/
bool CreateTableIfNotExist(string _name, DatabaseTableSchema &_schema) {
if (TableExists(_name)) {
return true;
}
return CreateTable(_name, _schema);
/**
* Creates table if not yet exist.
*/
bool CreateTableIfNotExist(string _name, DatabaseTableSchema &_schema) {
if (TableExists(_name)) {
return true;
}
return CreateTable(_name, _schema);
}

/**
* Creates table.
*/
bool CreateTable(string _name, DatabaseTableSchema &_schema) {
bool _result = false;
#ifdef __MQL5__
if (DatabaseTableExists(handle, _name)) {
// Generic error (ERR_DATABASE_ERROR).
SetUserError(5601);
return _result;
}
string query = "", subquery = "";
/**
* Creates table.
*/
bool CreateTable(string _name, DatabaseTableSchema &_schema) {
bool _result = false;
#ifndef __MQL4__
if (DatabaseTableExists(handle, _name)) {
// Generic error (ERR_DATABASE_ERROR).
SetUserError(5601);
return _result;
}

string query = "", subquery = "";

if (_schema.columns.Size() == 0) {
// SQLite does'nt allow tables without columns;
subquery = "`dummy` INTEGER";
} else {
for (DictStructIterator<short, DatabaseTableColumnEntry> iter = _schema.columns.Begin(); iter.IsValid(); ++iter) {
subquery +=
StringFormat("%s %s %s,", iter.Value().GetName(), iter.Value().GetDatatype(), iter.Value().GetFlags());
StringFormat("`%s` %s %s,", iter.Value().GetName(), iter.Value().GetDatatype(), iter.Value().GetFlags());
}
subquery = StringSubstr(subquery, 0, StringLen(subquery) - 1); // Removes extra comma.
query = StringFormat("CREATE TABLE %s(%s);", _name, subquery);
if (_result = DatabaseExecute(handle, query)) {
ResetLastError();
SetTableSchema(_name, _schema);
}
}

query = StringFormat("CREATE TABLE `%s`(%s);", _name, subquery);

#ifdef __debug__
Print("Database: Executing query:\n", query);
#endif

if (_result = DatabaseExecute(handle, query)) {
ResetLastError();
SetTableSchema(_name, _schema);
} else {
#ifdef __debug__
Print("Database: Query failed with error ", _LastError);
DebugBreak();
#endif
return _result;
}
#endif
return _result;
}

/**
* Drops table.
*/
bool DropTable(string _name) {
tables.Unset(_name);
#ifdef __MQL5__
return DatabaseExecute(handle, "DROP TABLE IF EXISTS " + _name);
/**
* Drops table.
*/
bool DropTable(string _name) {
tables.Unset(_name);
#ifndef __MQL4__
return DatabaseExecute(handle, "DROP TABLE IF EXISTS `" + _name + "`");
#else
return false;
#endif
}
}

/* Import methods */
/* Import methods */

/**
* Imports data into table. First row must contain column names. Strings must be enclosed with double quotes.
*/
bool ImportData(const string _name, MiniMatrix2d<string> &data) {
int x, y;
bool _result = true;
DatabaseTableSchema _schema = GetTableSchema(_name);
string _query = "", _cols = "", _vals = "";
for (x = 0; x < data.SizeX(); ++x) {
const string key = data.Get(x, 0);
_cols += "`" + StringSubstr(key, 1, StringLen(key) - 2) + "`,";
}
_cols = StringSubstr(_cols, 0, StringLen(_cols) - 1); // Removes extra comma.
#ifdef __MQL5__
if (DatabaseTransactionBegin(handle)) {
_query = StringFormat("INSERT INTO `%s`(%s) VALUES\n", _name, _cols);
for (y = 1; y < data.SizeY(); ++y) {
_query += "(";
for (x = 0; x < data.SizeX(); ++x) {
_query += data.Get(x, y) + (x < data.SizeX() - 1 ? ", " : "");
}
_query += ")" + (y < data.SizeY() - 1 ? ",\n" : "");
/**
* Imports data into table. First row must contain column names. Strings must be enclosed with double quotes.
*/
bool ImportData(const string _name, MiniMatrix2d<string> &data) {
if (data.SizeY() < 2 || data.SizeX() == 0) {
// No data to import or there are no columns in input data (Serialize() serialized no fields).
return true;
}
int x;
bool _result = true;
DatabaseTableSchema _schema = GetTableSchema(_name);
string _query = "", _cols = "", _vals = "";
for (x = 0; x < data.SizeX(); ++x) {
const string key = data.Get(x, 0);
_cols += "`" + StringSubstr(key, 1, StringLen(key) - 2) + "`,";
}
_cols = StringSubstr(_cols, 0, StringLen(_cols) - 1); // Removes extra comma.
#ifndef __MQL4__
if (DatabaseTransactionBegin(handle)) {
_query = StringFormat("INSERT INTO `%s`(%s) VALUES\n", _name, _cols);
for (int y = 1; y < data.SizeY(); ++y) {
_query += "(";
for (x = 0; x < data.SizeX(); ++x) {
_query += data.Get(x, y) + (x < data.SizeX() - 1 ? ", " : "");
}

_result &= DatabaseExecute(handle, _query);
}
if (_result) {
DatabaseTransactionCommit(handle);
} else {
DatabaseTransactionRollback(handle);
_query += ")" + (y < data.SizeY() - 1 ? ",\n" : "");
}

#ifdef __debug__
Print("Database: Executing query:\n", _query);
#endif

_result &= DatabaseExecute(handle, _query);
}
if (_result) {
DatabaseTransactionCommit(handle);
} else {
Print("Database: Query failed with error ", _LastError);
DebugBreak();
DatabaseTransactionRollback(handle);
}
#else
return false;
#endif
return _result;
}
return _result;
}

#ifdef BUFFER_STRUCT_MQH
/**
* Imports BufferStruct records into a table.
*/
template <typename TStruct>
bool Import(const string _name, BufferStruct<TStruct> &_bstruct) {
bool _result = true;
DatabaseTableSchema _schema = GetTableSchema(_name);
string _query = "", _cols = "", _vals = "";
for (DictStructIterator<short, DatabaseTableColumnEntry> iter = _schema.columns.Begin(); iter.IsValid(); ++iter) {
_cols += iter.Value().name + ",";
}
_cols = StringSubstr(_cols, 0, StringLen(_cols) - 1); // Removes extra comma.
#ifdef __MQL5__
if (DatabaseTransactionBegin(handle)) {
for (DictStructIterator<long, TStruct> iter = _bstruct.Begin(); iter.IsValid(); ++iter) {
_query = StringFormat("INSERT INTO %s(%s) VALUES (%s)", _name, _cols, iter.Value().ToCSV());
_result &= DatabaseExecute(handle, _query);
}
}
if (_result) {
DatabaseTransactionCommit(handle);
} else {
DatabaseTransactionRollback(handle);
/**
* Imports BufferStruct records into a table.
*/
template <typename TStruct>
bool Import(const string _name, BufferStruct<TStruct> &_bstruct) {
bool _result = true;
DatabaseTableSchema _schema = GetTableSchema(_name);
string _query = "", _cols = "", _vals = "";
for (DictStructIterator<short, DatabaseTableColumnEntry> iter = _schema.columns.Begin(); iter.IsValid(); ++iter) {
_cols += iter.Value().name + ",";
}
_cols = StringSubstr(_cols, 0, StringLen(_cols) - 1); // Removes extra comma.
#ifndef __MQL4__
if (DatabaseTransactionBegin(handle)) {
for (DictStructIterator<long, TStruct> iter = _bstruct.Begin(); iter.IsValid(); ++iter) {
_query = StringFormat("INSERT INTO %s(%s) VALUES (%s)", _name, _cols, iter.Value().ToCSV());
_result &= DatabaseExecute(handle, _query);
}
}
if (_result) {
DatabaseTransactionCommit(handle);
} else {
DatabaseTransactionRollback(handle);
}
#else
return false;
return false;
#endif
return _result;
}
return _result;
}
#endif

/* Getters */
/* Getters */

/**
* Gets database handle.
*/
int GetHandle() { return handle; }
/**
* Gets database handle.
*/
int GetHandle() { return handle; }

/**
* Gets table schema.
*/
DatabaseTableSchema GetTableSchema(string _name) { return tables.GetByKey(_name); }
/**
* Gets table schema.
*/
DatabaseTableSchema GetTableSchema(string _name) { return tables.GetByKey(_name); }

/**
* Checks if table schema exists.
*/
bool SchemaExists(string _name) { return tables.KeyExists(_name); }

/* Setters */
/* Setters */

/**
* Sets table schema.
*/
bool SetTableSchema(string _name, DatabaseTableSchema &_schema) { return tables.Set(_name, _schema); }
};
/**
* Sets table schema.
*/
bool SetTableSchema(string _name, DatabaseTableSchema &_schema) { return tables.Set(_name, _schema); }
}
;
#endif // DATABASE_MQH
2 changes: 2 additions & 0 deletions Dict.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ class Dict : public DictBase<K, V> {
_mode = DictModeDict;
else if (_mode != DictModeDict) {
Alert("Warning: Dict already operates as a list, not a dictionary!");
DebugBreak();
return false;
}

Expand Down Expand Up @@ -235,6 +236,7 @@ class Dict : public DictBase<K, V> {
_mode = DictModeList;
else if (_mode != DictModeList) {
Alert("Warning: Dict already operates as a dictionary, not a list!");
DebugBreak();
return false;
}

Expand Down
2 changes: 2 additions & 0 deletions DictObject.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@ class DictObject : public DictBase<K, V> {
_mode = DictModeDict;
else if (_mode != DictModeDict) {
Alert("Warning: Dict already operates as a list, not a dictionary!");
DebugBreak();
return false;
}

Expand Down Expand Up @@ -241,6 +242,7 @@ class DictObject : public DictBase<K, V> {
_mode = DictModeList;
else if (_mode != DictModeList) {
Alert("Warning: Dict already operates as a dictionary, not a list!");
DebugBreak();
return false;
}

Expand Down
3 changes: 3 additions & 0 deletions DictStruct.mqh
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,7 @@ class DictStruct : public DictBase<K, V> {

if (slot == NULL || !slot.IsUsed()) {
Alert("Invalid DictStruct key \"", key, "\" (called by [] operator). Returning empty structure.");
DebugBreak();
static V _empty;
return _empty;
}
Expand All @@ -160,6 +161,7 @@ class DictStruct : public DictBase<K, V> {

if (!slot) {
Alert("Invalid DictStruct key \"", _key, "\" (called by GetByKey()). Returning empty structure.");
DebugBreak();
static V _empty;
return _empty;
}
Expand All @@ -175,6 +177,7 @@ class DictStruct : public DictBase<K, V> {

if (!slot) {
Alert("Invalid DictStruct position \"", _position, "\" (called by GetByPos()). Returning empty structure.");
DebugBreak();
static V _empty;
return _empty;
}
Expand Down
Loading

0 comments on commit 3ee4114

Please sign in to comment.