513 lines
14 KiB
C++
513 lines
14 KiB
C++
|
|
#include <database/database.h>
|
|
|
|
// Set up DB
|
|
void marstr::database::setUpDatabase(string dbname, vector<string> fieldnames, vector<int> datatypes)
|
|
{
|
|
// Set the name
|
|
DatabaseName = dbname;
|
|
|
|
// Acquire the field names
|
|
int i;
|
|
for (i=1; i<=fieldnames.size(); i++)
|
|
{ FieldNames.push_back(fieldnames[i-1]); }
|
|
|
|
// Acquire the field data types
|
|
for (i=1; i<=datatypes.size(); i++)
|
|
{ RowDatatypes.push_back(datatypes[i-1]); }
|
|
}
|
|
|
|
|
|
// Adds a pre-created row
|
|
void marstr::database::addRow(databaserow row)
|
|
{
|
|
// Check if the row has the same amount of fields that we expect there to be
|
|
if (row.RowFields.size() == FieldNames.size())
|
|
{ Rows.push_back(row); }
|
|
}
|
|
|
|
|
|
// Deletes the specified row
|
|
void marstr::database::deleteRow(int rowNumber)
|
|
{
|
|
// Create a new vector with the specified row omitted
|
|
vector<databaserow> rows;
|
|
|
|
// Go through existing rows and add them to the above vector
|
|
// (except rowNumber)
|
|
int i;
|
|
for (i=1; i<=Rows.size(); i++)
|
|
{
|
|
if (i!=rowNumber)
|
|
{ rows.push_back(Rows[i-1]); }
|
|
}
|
|
|
|
// Now clear the real vector
|
|
Rows.clear();
|
|
|
|
// And add the rows we got to the real rows
|
|
for (i=1; i<=rows.size(); i++)
|
|
{ Rows.push_back(rows[i-1]); }
|
|
|
|
// Clear the tmp vector
|
|
rows.clear();
|
|
}
|
|
|
|
|
|
// Updates the content of a specific field in a specific row
|
|
void marstr::database::updateFieldInRow(int rowNumber, int fieldNumber, string content)
|
|
{
|
|
// Make sure the row and field exist
|
|
if (rowNumber <= Rows.size() && fieldNumber <= FieldNames.size())
|
|
{
|
|
// When updating a field, it is probably not a null field
|
|
Rows[rowNumber].RowFields[fieldNumber].NullField = false;
|
|
|
|
// It can be either one of these... so make sure they exist
|
|
int newInt = 0;
|
|
short newShort = 0;
|
|
float newFloat = 0.0f;
|
|
double newDouble = 0.0f;
|
|
string newString = content;
|
|
|
|
// Find the datatype for the field
|
|
int datatype = RowDatatypes[fieldNumber];
|
|
|
|
// Convert the field
|
|
if (datatype == MARSTR_DB_INT)
|
|
{
|
|
newInt = atoi(content.c_str());
|
|
Rows[rowNumber].RowFields[fieldNumber].fieldInt = newInt;
|
|
}
|
|
if (datatype == MARSTR_DB_SHORT)
|
|
{
|
|
newShort = atoi(content.c_str());
|
|
Rows[rowNumber].RowFields[fieldNumber].fieldShort = newShort;
|
|
}
|
|
if (datatype == MARSTR_DB_FLOAT)
|
|
{
|
|
newFloat = atof(content.c_str());
|
|
Rows[rowNumber].RowFields[fieldNumber].fieldFloat = newFloat;
|
|
}
|
|
if (datatype == MARSTR_DB_DOUBLE)
|
|
{
|
|
newDouble = atof(content.c_str());
|
|
Rows[rowNumber].RowFields[fieldNumber].fieldDouble = newDouble;
|
|
}
|
|
if (datatype == MARSTR_DB_STRING)
|
|
{ Rows[rowNumber].RowFields[fieldNumber].fieldString = content; }
|
|
}
|
|
}
|
|
|
|
|
|
// Defines a field to be a null field or not
|
|
void marstr::database::fieldIsNullField(int rowNumber, int fieldNumber, bool isNull)
|
|
{
|
|
// Make sure the row and field exist
|
|
if (rowNumber <= Rows.size() && fieldNumber <= FieldNames.size())
|
|
{ Rows[rowNumber].RowFields[fieldNumber].NullField = isNull; }
|
|
}
|
|
|
|
|
|
// Creates an empty db to be filled later
|
|
void marstr::database::createDatabase(string filename, string dbname, vector<string> fieldnames, vector<int> datatypes)
|
|
{
|
|
setUpDatabase(dbname, fieldnames, datatypes);
|
|
}
|
|
|
|
|
|
|
|
// Load database, but only the header - no content
|
|
void marstr::database::openDatabaseLink(string filename)
|
|
{
|
|
// Remember file name
|
|
DatabaseFileName = filename;
|
|
|
|
// File IO object
|
|
_linkIO = new fileio();
|
|
|
|
// Open DB
|
|
_linkIO->openFileForReading(filename);
|
|
|
|
// Read header and version
|
|
string hdrString = _linkIO->readString();
|
|
float hdrVersion = _linkIO->readFloat();
|
|
|
|
// Check if the header works out
|
|
string hdrStringCheck = "MARSTRDB";
|
|
if (hdrVersion == 1) // String check to be implemented
|
|
{
|
|
// Then this is a valid database
|
|
DatabaseFileName = filename;
|
|
|
|
// Read database name
|
|
DatabaseName = _linkIO->readString();
|
|
|
|
// Get number of field names
|
|
int amountOfFields = _linkIO->readInt();
|
|
|
|
// Read in the field names themselves
|
|
int i, j;
|
|
for (i=1; i<=amountOfFields; i++)
|
|
{ FieldNames.push_back(_linkIO->readString()); }
|
|
|
|
// Acquire the data types of each field
|
|
for (i=1; i<=amountOfFields; i++)
|
|
{ RowDatatypes.push_back(_linkIO->readInt()); }
|
|
|
|
// Number of rows in total
|
|
int numberOfRows = _linkIO->readInt();
|
|
}
|
|
}
|
|
|
|
|
|
databaserow marstr::database::nextDatabaseRow()
|
|
{
|
|
// The row to be constructed
|
|
databaserow row;
|
|
|
|
for (int j=1; j<=FieldNames.size(); j++)
|
|
{
|
|
// The field to be added to the row
|
|
databasefield fld;
|
|
|
|
// OK find out if the field has content (null field)
|
|
int isNullField = _linkIO->readInt();
|
|
|
|
// If this is a null field, set the field to be so and add it
|
|
// to the row
|
|
if (isNullField == 1)
|
|
{ fld.NullField = true; row.RowFields.push_back(fld); }
|
|
|
|
// If we have data, read according to the data type, set the
|
|
// value into the field, and add the field to the row
|
|
if (isNullField == 0)
|
|
{
|
|
// Not a null field
|
|
fld.NullField = false;
|
|
|
|
if (RowDatatypes[j-1] == MARSTR_DB_INT)
|
|
{ int fldval = _linkIO->readInt(); fld.fieldInt = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_UINT)
|
|
{ unsigned int fldval = _linkIO->readUInt(); fld.fieldUInt = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_SHORT)
|
|
{ short fldval = _linkIO->readInt(); fld.fieldShort = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_USHORT)
|
|
{ unsigned short fldval = _linkIO->readUShort(); fld.fieldUShort = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_LONG)
|
|
{ long fldval = _linkIO->readLong(); fld.fieldLong = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_ULONG)
|
|
{ unsigned long fldval = _linkIO->readULong(); fld.fieldULong = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_FLOAT)
|
|
{ float fldval = _linkIO->readFloat(); fld.fieldFloat = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_DOUBLE)
|
|
{ double fldval = _linkIO->readDouble(); fld.fieldDouble = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_STRING)
|
|
{ string fldval = _linkIO->readString(); fld.fieldString = fldval; }
|
|
|
|
// Add the field
|
|
row.RowFields.push_back(fld);
|
|
}
|
|
}
|
|
|
|
return row;
|
|
}
|
|
|
|
|
|
void marstr::database::goToFirstRow()
|
|
{
|
|
_linkIO->closeFileForReading();
|
|
openDatabaseLink(DatabaseFileName);
|
|
}
|
|
|
|
|
|
// Loads a database from file
|
|
void marstr::database::loadDatabase(string filename)
|
|
{
|
|
// File IO object
|
|
fileio *FileIO = new fileio();
|
|
|
|
// Remember file name
|
|
DatabaseFileName = filename;
|
|
|
|
// Open DB
|
|
FileIO->openFileForReading(filename);
|
|
|
|
// Read header and version
|
|
string hdrString = FileIO->readString();
|
|
float hdrVersion = FileIO->readFloat();
|
|
|
|
// Check if the header works out
|
|
string hdrStringCheck = "MARSTRDB";
|
|
if (hdrVersion == 1) // String check to be implemented
|
|
{
|
|
// Then this is a valid database
|
|
DatabaseFileName = filename;
|
|
|
|
// Read database name
|
|
DatabaseName = FileIO->readString();
|
|
|
|
// Get number of field names
|
|
int amountOfFields = FileIO->readInt();
|
|
|
|
// Read in the field names themselves
|
|
int i, j;
|
|
for (i=1; i<=amountOfFields; i++)
|
|
{ FieldNames.push_back(FileIO->readString()); }
|
|
|
|
// Acquire the data types of each field
|
|
for (i=1; i<=amountOfFields; i++)
|
|
{ RowDatatypes.push_back(FileIO->readInt()); }
|
|
|
|
// Number of rows in total
|
|
int numberOfRows = FileIO->readInt();
|
|
|
|
// Go through the remainder of the file to acquire the content
|
|
// of each row and their fields
|
|
for (i=1; i<=numberOfRows; i++)
|
|
{
|
|
// The row to be constructed
|
|
databaserow row;
|
|
|
|
for (j=1; j<=FieldNames.size(); j++)
|
|
{
|
|
// The field to be added to the row
|
|
databasefield fld;
|
|
|
|
// OK find out if the field has content (null field)
|
|
int isNullField = FileIO->readInt();
|
|
|
|
// If this is a null field, set the field to be so and add it
|
|
// to the row
|
|
if (isNullField == 1)
|
|
{ fld.NullField = true; row.RowFields.push_back(fld); }
|
|
|
|
// If we have data, read according to the data type, set the
|
|
// value into the field, and add the field to the row
|
|
if (isNullField == 0)
|
|
{
|
|
// Not a null field
|
|
fld.NullField = false;
|
|
|
|
if (RowDatatypes[j-1] == MARSTR_DB_INT)
|
|
{ int fldval = FileIO->readInt(); fld.fieldInt = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_UINT)
|
|
{ unsigned int fldval = FileIO->readUInt(); fld.fieldUInt = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_SHORT)
|
|
{ short fldval = FileIO->readInt(); fld.fieldShort = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_USHORT)
|
|
{ unsigned short fldval = FileIO->readUShort(); fld.fieldUShort = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_LONG)
|
|
{ long fldval = FileIO->readLong(); fld.fieldLong = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_ULONG)
|
|
{ unsigned long fldval = FileIO->readULong(); fld.fieldULong = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_FLOAT)
|
|
{ float fldval = FileIO->readFloat(); fld.fieldFloat = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_DOUBLE)
|
|
{ double fldval = FileIO->readDouble(); fld.fieldDouble = fldval; }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_STRING)
|
|
{ string fldval = FileIO->readString(); fld.fieldString = fldval; }
|
|
|
|
// Add the field
|
|
row.RowFields.push_back(fld);
|
|
}
|
|
}
|
|
|
|
// Add the completed row
|
|
Rows.push_back(row);
|
|
}
|
|
|
|
// Magic number check
|
|
int Magic = (Rows.size() * RowDatatypes.size());
|
|
int MagicInFile = FileIO->readInt();
|
|
|
|
// If the magic does not stack up, clear all data
|
|
if (Magic != MagicInFile)
|
|
{ Rows.clear(); }
|
|
}
|
|
|
|
// Close the pipe
|
|
FileIO->closeFileForReading();
|
|
|
|
// That's it
|
|
}
|
|
|
|
|
|
// Saves the database to the specified file. Use when everything is done!
|
|
void marstr::database::saveDatabase()
|
|
{
|
|
// File IO object// File IO object
|
|
fileio *FileIO = new fileio();
|
|
|
|
// Open the DB
|
|
FileIO->openFileForWriting(DatabaseFileName);
|
|
|
|
// Write a header
|
|
FileIO->writeString("MARSTRDB");
|
|
// Write a version
|
|
FileIO->writeFloat(1.0);
|
|
|
|
// Write database name
|
|
FileIO->writeString(DatabaseName);
|
|
|
|
// Write number of field names
|
|
FileIO->writeInt(FieldNames.size());
|
|
|
|
// The field names themselves
|
|
int i, j;
|
|
for (i=1; i<=FieldNames.size(); i++)
|
|
{ FileIO->writeString(FieldNames[i-1]); }
|
|
|
|
// The datatypes in each field
|
|
for (i=1; i<=RowDatatypes.size(); i++)
|
|
{ FileIO->writeInt(RowDatatypes[i-1]); }
|
|
|
|
// Write number of rows
|
|
FileIO->writeInt(Rows.size());
|
|
|
|
// Go through the rows and write the content, depending on if the field is
|
|
// a null field or not
|
|
for (i=1; i<=Rows.size(); i++)
|
|
{
|
|
for (j=1; j<=Rows[i-1].RowFields.size(); j++)
|
|
{
|
|
// Write down an int to signalize if the field has data or not
|
|
int isNull = 0;
|
|
if (Rows[i-1].RowFields[j-1].NullField == true) { isNull = 1; }
|
|
if (Rows[i-1].RowFields[j-1].NullField == false) { isNull = 0; }
|
|
FileIO->writeInt(isNull);
|
|
|
|
// Write actual data if field is not null
|
|
if (isNull == 0)
|
|
{
|
|
if (RowDatatypes[j-1] == MARSTR_DB_SHORT) // short
|
|
{ FileIO->writeInt(Rows[i-1].RowFields[j-1].fieldShort); }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_INT) // int
|
|
{ FileIO->writeInt(Rows[i-1].RowFields[j-1].fieldInt); }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_UINT) // uint
|
|
{ FileIO->writeUInt(Rows[i-1].RowFields[j-1].fieldUInt); }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_LONG) // long
|
|
{ FileIO->writeLong(Rows[i-1].RowFields[j-1].fieldLong); }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_ULONG) // ulong
|
|
{ FileIO->writeULong(Rows[i-1].RowFields[j-1].fieldULong); }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_FLOAT) // float
|
|
{ FileIO->writeFloat(Rows[i-1].RowFields[j-1].fieldFloat); }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_DOUBLE) // double
|
|
{ FileIO->writeDouble(Rows[i-1].RowFields[j-1].fieldDouble); }
|
|
if (RowDatatypes[j-1] == MARSTR_DB_STRING) // string
|
|
{ FileIO->writeString(Rows[i-1].RowFields[j-1].fieldString); }
|
|
}
|
|
}
|
|
}
|
|
|
|
// Write a magic number for verification
|
|
int Magic = (Rows.size() * RowDatatypes.size());
|
|
FileIO->writeInt(Magic);
|
|
|
|
|
|
// Close DB
|
|
FileIO->closeFileForWriting();
|
|
|
|
// That's it
|
|
}
|
|
|
|
|
|
void marstr::database::closeDatabase(bool save)
|
|
{
|
|
if (save == true)
|
|
{ saveDatabase(); }
|
|
|
|
Rows.clear();
|
|
}
|
|
|
|
|
|
vector<int> marstr::database::findRowsWithValueInColumn(string value, string colname)
|
|
{
|
|
// The result with the index IDs
|
|
vector<int> rows;
|
|
|
|
// The column index to be searched
|
|
int colindex = -1;
|
|
for (int i=0; i<FieldNames.size(); i++)
|
|
{
|
|
if (FieldNames[i].compare(colname) == 0)
|
|
{ colindex = i; break; }
|
|
}
|
|
|
|
// Proceed if we have a column
|
|
if (colindex != -1)
|
|
{
|
|
// Look for results depending on datatype
|
|
for (int i=0; i<Rows.size(); i++)
|
|
{
|
|
bool push=false;
|
|
|
|
// The field to check
|
|
databasefield fld = Rows[i].RowFields[colindex];
|
|
|
|
if (RowDatatypes[colindex] == MARSTR_DB_INT)
|
|
{
|
|
int needle = stoi(value);
|
|
if (fld.NullField == false && fld.fieldInt == needle)
|
|
{ push = true; }
|
|
}
|
|
if (RowDatatypes[colindex] == MARSTR_DB_UINT)
|
|
{
|
|
unsigned int needle = stoi(value);
|
|
if (fld.NullField == false && fld.fieldUInt == needle)
|
|
{ push = true; }
|
|
}
|
|
if (RowDatatypes[colindex] == MARSTR_DB_SHORT)
|
|
{
|
|
short needle = stoi(value);
|
|
if (fld.NullField == false && fld.fieldShort == needle)
|
|
{ push = true; }
|
|
}
|
|
if (RowDatatypes[colindex] == MARSTR_DB_USHORT)
|
|
{
|
|
unsigned short needle = stoi(value);
|
|
if (fld.NullField == false && fld.fieldUShort == needle)
|
|
{ push = true; }
|
|
}
|
|
if (RowDatatypes[colindex] == MARSTR_DB_LONG)
|
|
{
|
|
long needle = stol(value);
|
|
if (fld.NullField == false && fld.fieldLong == needle)
|
|
{ push = true; }
|
|
}
|
|
if (RowDatatypes[colindex] == MARSTR_DB_ULONG)
|
|
{
|
|
long needle = stol(value);
|
|
if (fld.NullField == false && fld.fieldULong == needle)
|
|
{ push = true; }
|
|
}
|
|
if (RowDatatypes[colindex] == MARSTR_DB_FLOAT)
|
|
{
|
|
float needle = stof(value);
|
|
if (fld.NullField == false && fld.fieldFloat == needle)
|
|
{ push = true; }
|
|
}
|
|
if (RowDatatypes[colindex] == MARSTR_DB_DOUBLE)
|
|
{
|
|
double needle = stod(value);
|
|
if (fld.NullField == false && fld.fieldDouble == needle)
|
|
{ push = true; }
|
|
}
|
|
if (RowDatatypes[colindex] == MARSTR_DB_STRING)
|
|
{
|
|
if (fld.NullField == false && fld.fieldString.compare(value) == 0)
|
|
{ push = true; }
|
|
}
|
|
|
|
if (push == true) { rows.push_back(i); }
|
|
}
|
|
}
|
|
|
|
// Return list
|
|
return rows;
|
|
}
|
|
|
|
|
|
|
|
int marstr::database::numberOfRows() { return Rows.size(); }
|