////////////////////////////////////////////////////////////////////////
// OpenTibia - an opensource roleplaying game
////////////////////////////////////////////////////////////////////////
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
////////////////////////////////////////////////////////////////////////
#ifndef __DATABASE__
#define __DATABASE__
#include "otsystem.h"
#include "enums.h"
#include
#ifdef MULTI_SQL_DRIVERS
#define DATABASE_VIRTUAL virtual
#define DATABASE_CLASS _Database
#define DBRES_CLASS _DBResult
class _Database;
class _DBResult;
#else
#define DATABASE_VIRTUAL
#if defined(__USE_MYSQL__)
#define DATABASE_CLASS DatabaseMySQL
#define DBRES_CLASS MySQLResult
class DatabaseMySQL;
class MySQLResult;
#elif defined(__USE_SQLITE__)
#define DATABASE_CLASS DatabaseSQLite
#define DBRES_CLASS SQLiteResult
class DatabaseSQLite;
class SQLiteResult;
#elif defined(__USE_ODBC__)
#define DATABASE_CLASS DatabaseODBC
#define DBRES_CLASS ODBCResult
class DatabaseODBC;
class ODBCResult;
#elif defined(__USE_PGSQL__)
#define DATABASE_CLASS DatabasePgSQL
#define DBRES_CLASS PgSQLResult
class DatabasePgSQL;
class PgSQLResult;
#endif
#endif
#ifndef DATABASE_CLASS
#error "You have to compile with at least one database driver!"
#define DBResult void
#define DBInsert void*
#define Database void
#else
typedef DATABASE_CLASS Database;
typedef DBRES_CLASS DBResult;
class DBQuery;
enum DBParam_t
{
DBPARAM_MULTIINSERT = 1
};
class _Database
{
public:
/**
* Singleton implementation.
*
* Retruns instance of database handler. Don't create database (or drivers) instances in your code - instead of it use Database::getInstance(). This method stores static instance of connection class internaly to make sure exacly one instance of connection is created for entire system.
*
* @return database connection handler singletor
*/
static Database* getInstance();
/**
* Database information.
*
* Returns currently used database attribute.
*
* @param DBParam_t parameter to get
* @return suitable for given parameter
*/
DATABASE_VIRTUAL bool getParam(DBParam_t param) {return false;}
/**
* Database connected.
*
* Returns whether or not the database is connected.
*
* @return whether or not the database is connected.
*/
DATABASE_VIRTUAL bool isConnected() {return m_connected;}
/**
* Database ...
*/
DATABASE_VIRTUAL void use() {m_use = time(NULL);}
protected:
/**
* Transaction related methods.
*
* Methods for starting, commiting and rolling back transaction. Each of the returns boolean value.
*
* @return true on success, false on error
* @note
* If your database system doesn't support transactions you should return true - it's not feature test, code should work without transaction, just will lack integrity.
*/
friend class DBTransaction;
DATABASE_VIRTUAL bool beginTransaction() {return 0;}
DATABASE_VIRTUAL bool rollback() {return 0;}
DATABASE_VIRTUAL bool commit() {return 0;}
public:
/**
* Executes command.
*
* Executes query which doesn't generates results (eg. INSERT, UPDATE, DELETE...).
*
* @param std::string query command
* @return true on success, false on error
*/
DATABASE_VIRTUAL bool executeQuery(const std::string &query) {return 0;}
/**
* Queries database.
*
* Executes query which generates results (mostly SELECT).
*
* @param std::string query
* @return results object (null on error)
*/
DATABASE_VIRTUAL DBResult* storeQuery(const std::string &query) {return 0;}
/**
* Escapes string for query.
*
* Prepares string to fit SQL queries including quoting it.
*
* @param std::string string to be escaped
* @return quoted string
*/
DATABASE_VIRTUAL std::string escapeString(const std::string &s) {return "''";}
/**
* Escapes binary stream for query.
*
* Prepares binary stream to fit SQL queries.
*
* @param char* binary stream
* @param long stream length
* @return quoted string
*/
DATABASE_VIRTUAL std::string escapeBlob(const char* s, uint32_t length) {return "''";}
/**
* Retrieve id of last inserted row
*
* @return id on success, 0 if last query did not result on any rows with auto_increment keys
*/
DATABASE_VIRTUAL uint64_t getLastInsertId() {return 0;}
/**
* Get case insensitive string comparison operator
*
* @return the case insensitive operator
*/
DATABASE_VIRTUAL std::string getStringComparison() {return "=";}
DATABASE_VIRTUAL std::string getUpdateLimiter() {return " LIMIT 1";}
/**
* Get database engine
*
* @return the database engine type
*/
DATABASE_VIRTUAL DatabaseEngine_t getDatabaseEngine() {return DATABASE_ENGINE_NONE;}
protected:
_Database() {}
DATABASE_VIRTUAL ~_Database() {}
DBResult* verifyResult(DBResult* result);
bool m_connected;
time_t m_use;
private:
static Database* _instance;
};
class _DBResult
{
public:
/** Get the Integer value of a field in database
*\returns The Integer value of the selected field and row
*\param s The name of the field
*/
DATABASE_VIRTUAL int32_t getDataInt(const std::string &s) {return 0;}
/** Get the Long value of a field in database
*\returns The Long value of the selected field and row
*\param s The name of the field
*/
DATABASE_VIRTUAL int64_t getDataLong(const std::string &s) {return 0;}
/** Get the String of a field in database
*\returns The String of the selected field and row
*\param s The name of the field
*/
DATABASE_VIRTUAL std::string getDataString(const std::string &s) {return "''";}
/** Get the blob of a field in database
*\returns a PropStream that is initiated with the blob data field, if not exist it returns NULL.
*\param s The name of the field
*/
DATABASE_VIRTUAL const char* getDataStream(const std::string &s, uint64_t &size) {return 0;}
/** Result freeing
*/
DATABASE_VIRTUAL void free() {/*delete this;*/}
/** Moves to next result in set
*\returns true if moved, false if there are no more results.
*/
DATABASE_VIRTUAL bool next() {return false;}
protected:
_DBResult() {}
DATABASE_VIRTUAL ~_DBResult() {}
};
/**
* Thread locking hack.
*
* By using this class for your queries you lock and unlock database for threads.
*/
class DBQuery : public std::stringstream
{
friend class _Database;
public:
DBQuery() {OTSYS_THREAD_LOCK(databaseLock, "");}
virtual ~DBQuery() {str(""); OTSYS_THREAD_UNLOCK(databaseLock, "");}
protected:
static OTSYS_THREAD_LOCKVAR databaseLock;
};
/**
* INSERT statement.
*
* Gives possibility to optimize multiple INSERTs on databases that support multiline INSERTs.
*/
class DBInsert
{
public:
/**
* Associates with given database handler.
*
* @param Database* database wrapper
*/
DBInsert(Database* db);
virtual ~DBInsert() {}
/**
* Sets query prototype.
*
* @param std::string& INSERT query
*/
void setQuery(const std::string& query);
/**
* Adds new row to INSERT statement.
*
* On databases that doesn't support multiline INSERTs it simply execute INSERT for each row.
*
* @param std::string& row data
*/
bool addRow(const std::string& row);
/**
* Allows to use addRow() with stringstream as parameter.
*/
bool addRow(std::stringstream& row);
/**
* Executes current buffer.
*/
bool execute();
protected:
Database* m_db;
bool m_multiLine;
uint32_t m_rows;
std::string m_query, m_buf;
};
#ifndef MULTI_SQL_DRIVERS
#if defined(__USE_MYSQL__)
#include "databasemysql.h"
#elif defined(__USE_SQLITE__)
#include "databasesqlite.h"
#elif defined(__USE_ODBC__)
#include "databaseodbc.h"
#elif defined(__USE_PGSQL__)
#include "databasepgsql.h"
#endif
#endif
class DBTransaction
{
public:
DBTransaction(Database* database)
{
m_database = database;
m_state = STATE_NO_START;
}
virtual ~DBTransaction()
{
if(m_state == STATE_START)
m_database->rollback();
}
bool begin()
{
m_state = STATE_START;
return m_database->beginTransaction();
}
bool commit()
{
if(m_state != STATE_START)
return false;
m_state = STEATE_COMMIT;
return m_database->commit();
}
private:
enum TransactionStates_t
{
STATE_NO_START,
STATE_START,
STEATE_COMMIT
};
TransactionStates_t m_state;
Database* m_database;
};
#endif
#endif