DB::Db
DB::Db - это абстрактный базовый класс, реализующий идиому pimpl - pointer to implementation.
Он предоставляет обобщенный интерфейс для настройки подключения к СУБД и указатель pimpl
для доступа объектов DB::Tr и DB::Query к физическому интерфейсу СУБД. Для создания объектов
класса, как и для всех базовых классов в системе, нужно использовать фабричный метод
make с типом СУБД в качестве простого символьного параметра. Фабричный метод класса Db
использует фабрику DB::DbFactory которая является синглтоном. Так-же DB::Db содержит
указатели на функции производящие наследников Tr и Query.
Рассмотрим определение класса Db:
namespace DB
{
class Db;
typedef std::tr1::shared_ptr DbPtr;
class Db
{
public:
void SetServer(const std::string &value) { server = value; }
std::string GetServer() { return server; }
void SetDatabase(const std::string &value) { database = value; }
std::string GetDatabase() { return database; }
void SetUser(const std::string &value) { user = value; }
std::string GetUser() { return user; }
void SetPassword(const std::string &value) { password = value; }
std::string GetPassword() { return password; }
void SetRole(const std::string &value) { role = value; }
std::string GetRole() { return role; }
void SetCharset(const std::string &value) { charset = value; }
std::string GetCharset() { return charset; }
virtual bool Connected() = 0;
virtual void Connect() = 0;
virtual void Disconnect() = 0;
static DbPtr make(const std::string &);
virtual ~Db() {}
protected:
std::string server, database, user, password, role, charset;
bool connectdue;
typedef std::tr1::shared_ptr ImplPtr;
ImplPtr pimpl;
void MakeImpl();
Db() {}
public:
ImplPtr GetImpl() { return pimpl; }
typedef Tr* (*CreateTrCallback)(DbPtr);
typedef Query* (*CreateQueryCallback)(DbPtr, TrPtr);
CreateTrCallback CreateTr;
CreateQueryCallback CreateQuery;
};
}
Пользовательский интерфейс очевиден, нам как разработчикам интересна реализация
механизма pimpl, а также производство наследников. Pimpl реализован очень просто.
Имеется класс (описанный в хидере db/dbimpl.h) DbImpl содержащий объекты БД
(например IBPP::Database) для каждой СУБД:
namespace DB
{
class DbImpl
{
public:
#ifdef USE_FB
IBPP::Database fbdb;
#endif
#ifdef USE_MYSQL
MYSQL *mysqldb;
#endif
DbImpl() { ++guid; id = guid; }
int GetId() { return id; }
private:
static int guid;
int id;
};
}
Конструктор класса задает уникальный id для объекта, этот id нужен для определения при создании DB::Query принадлежит ли объект транзакции объекту БД.
Поскольку создание объектов физических БД в DbImpl происходит в члене Db Connect() введена
переменная connectdue. Её нужно использовать в реализации Connected() и вызывать
pimpl->mydb->Connected() только если она true.
Для создания pimpl в Db, конструкторы наследников должны вызвать метод MakeImpl().
Производство наследников Tr и Query осуществляется при помощи указателей на функции CreateTr и CreateQuery.
DB::Query
DB::Query - основной интерфейс к sql данным. Он обрабатывает sql запросы и позволяет получить доступ к результирующей выборке,
а так-же используется для выполнения запросов update, insert и delete.
В отличие от Db и Tr идиома pimpl здесь не используется, класс является обычным абстрактным
базовым с невиртуальным интерфейсом. Наследники должны реализовать только виртуальные функции.
Через pimpl Db и Tr имеется возможность получить доступ к физическому интерфейсу БД и транзакции.
Поскольку все наследники должны реализовать определенное поведение, класс будет рассмотрен максимально подробно.
Определение класса:
namespace DB
{
struct Date
{
int day, month, year;
};
struct Time
{
int sec, min, hour;
};
struct DateTime
{
int day, month, year, sec, min, hour;;
};
enum FieldType
{
int_,
float_,
double_,
string_,
date_,
time_,
timestamp_,
blob_
};
class Query;
typedef std::tr1::shared_ptr QueryPtr;
class Query
{
public:
virtual void SetSQL(const std::string &sql) = 0;
virtual void SetParam(const size_t ord, const int value) = 0; //ord - param order, start from 0
virtual void SetParam(const size_t ord, const float &value) = 0;
virtual void SetParam(const size_t ord, const double &value) = 0;
virtual void SetParam(const size_t ord, const std::string &value) = 0;
virtual void SetParam(const size_t ord, const Date &value) = 0;
virtual void SetParam(const size_t ord, const Time &value) = 0;
virtual void SetParam(const size_t ord, const DateTime &value) = 0;
virtual void SetBlobParam(const size_t ord, const std::string &value) = 0;
virtual void ExecSQL() = 0;
virtual void Open() = 0;
virtual void Close() = 0;
virtual size_t GetFieldsCount() = 0;
virtual std::string GetFieldName(const size_t field_n) = 0;
virtual FieldType GetFieldType(const size_t field_n) = 0;
virtual bool Fetch() = 0;
virtual int GetIntFieldValue(const size_t field_n) = 0;
virtual float GetFloatFieldValue(const size_t field_n) = 0;
virtual double GetDoubleFieldValue(const size_t field_n) = 0;
virtual std::string GetStrFieldValue(const size_t field_n) = 0;
virtual Date GetDateFieldValue(const size_t field_n) = 0;
virtual Time GetTimeFieldValue(const size_t field_n) = 0;
virtual DateTime GetDateTimeFieldValue(const size_t field_n) = 0;
virtual std::string GetBlobFieldValue(const size_t field_n) = 0;
static QueryPtr make(DbPtr, TrPtr);
virtual ~Query() {}
protected:
Query() {}
};
}
Расмотрим подробнее каждую функцию член:
void SetSQL(const std::string &sql) - Устанавливает sql запрос.
Запрос может быть параматерическим. Для обозначения параметра используется символ ?.
Например: select * from table where id = ?
void SetParam(const int ord, const TYPE &value) - Устанавливает значение параметра с номером ord.
Нумерация параметров начинается с нуля. Имеется 7 перегруженных функций для каждого поддерживаемого типа поля.
void SetBlobParam(const int ord, const std::string &value) - Аналогично, SetParam, но предназначена специально для blob полей.
void ExecSQL() - Запуск не возвращающего данных sql запроса.
void Open() - Запуск sql запроса, возвращающего данные.
void Close() - Закрытие набора данных и очистка кэша.
int GetFieldsCount() - Возвращает количество полей в выборке.
std::string GetFieldName(const int n) - Возвращает имя поля, по номеру в выборке. Нумерация с 0.
FieldType GetFieldType(const int n) - Возвращает тип поля
bool Fetch() - Перемещает "курсор" в выборке на одну позицию вниз и возвращает true если не достигнут конец выборки.
int GetIntFieldValue(const int n) - Возвращает значение поля типа int с номером n (нумерация с 0). Для остальных типов аналогично.
std::string GetStrFieldValue(const int n) - Возвращает значение поля в виде строки. Эта функция должна возвращать данные для ВСЕХ типов в преобразованном к string виду.
Реализация фабричного метода аналогична Tr::make:
using namespace DB;
QueryPtr Query::make(DbPtr db, TrPtr tr)
{
CheckDBConnected(db);
if (db->GetImpl()->GetId() != tr->GetImpl()->GetDbId())
{
throw EXC::exception("Transaction belongs to another object Db.");
}
return QueryPtr(db->CreateQuery(db, tr));
}
Как видно, здесь осуществляется проверка подключена ли БД и соответсвует ли транзакция указанному объекту БД.