mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-21 15:12:02 +00:00
mysqlxx: development.
This commit is contained in:
parent
29049005d1
commit
1cd2568ebb
@ -21,6 +21,8 @@ public:
|
||||
const char* password = 0,
|
||||
unsigned int port = 0);
|
||||
|
||||
Connection(const std::string & config_name);
|
||||
|
||||
virtual ~Connection();
|
||||
|
||||
virtual void connect(const char* db,
|
||||
|
@ -9,7 +9,21 @@
|
||||
namespace mysqlxx
|
||||
{
|
||||
|
||||
POCO_DECLARE_EXCEPTION(Foundation_API, Exception, Poco::Exception);
|
||||
struct Exception : public Poco::Exception
|
||||
{
|
||||
Exception(const std::string & msg, int code = 0) : Poco::Exception(msg, code) {}
|
||||
int errnum() { return code(); }
|
||||
};
|
||||
|
||||
struct ConnectionFailed : public Exception
|
||||
{
|
||||
ConnectionFailed(const std::string & msg, int code = 0) : Exception(msg, code) {}
|
||||
};
|
||||
|
||||
struct BadQuery : public Exception
|
||||
{
|
||||
BadQuery(const std::string & msg, int code = 0) : Exception(msg, code) {}
|
||||
};
|
||||
|
||||
|
||||
inline void checkError(MYSQL & driver)
|
||||
|
218
libs/libmysqlxx/include/mysqlxx/Manip.h
Normal file
218
libs/libmysqlxx/include/mysqlxx/Manip.h
Normal file
@ -0,0 +1,218 @@
|
||||
#ifndef MYSQLXX_MANIP_H
|
||||
#define MYSQLXX_MANIP_H
|
||||
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <mysqlxx/Types.h>
|
||||
|
||||
|
||||
namespace mysqlxx
|
||||
{
|
||||
|
||||
/** @brief Манипулятор ostream, который escape-ит строки для записи в tab delimited файл. */
|
||||
enum escape_enum
|
||||
{
|
||||
escape
|
||||
};
|
||||
|
||||
|
||||
/** @brief Манипулятор ostream, который quote-ит строки для записи в MySQL запрос.
|
||||
* Внимание! Не использует функции MySQL API, а использует свой метод quote-инга,
|
||||
* который может быть некорректным при использовании некоторых японских кодировок
|
||||
* (multi-byte attack), а также может оказаться некорректным при изменении libmysqlclient.
|
||||
* Это сделано для увеличения производительности и это имеет значение.
|
||||
*/
|
||||
enum quote_enum
|
||||
{
|
||||
quote
|
||||
};
|
||||
|
||||
|
||||
struct EscapeManipResult
|
||||
{
|
||||
std::ostream & ostr;
|
||||
|
||||
EscapeManipResult(std::ostream & ostr_) : ostr(ostr_) {}
|
||||
|
||||
std::ostream & operator<< (bool value) { return ostr << value; }
|
||||
std::ostream & operator<< (char value) { return ostr << value; }
|
||||
std::ostream & operator<< (unsigned char value) { return ostr << value; }
|
||||
std::ostream & operator<< (signed char value) { return ostr << value; }
|
||||
std::ostream & operator<< (short value) { return ostr << value; }
|
||||
std::ostream & operator<< (unsigned short value) { return ostr << value; }
|
||||
std::ostream & operator<< (int value) { return ostr << value; }
|
||||
std::ostream & operator<< (unsigned int value) { return ostr << value; }
|
||||
std::ostream & operator<< (long value) { return ostr << value; }
|
||||
std::ostream & operator<< (unsigned long value) { return ostr << value; }
|
||||
std::ostream & operator<< (float value) { return ostr << value; }
|
||||
std::ostream & operator<< (double value) { return ostr << value; }
|
||||
std::ostream & operator<< (long long value) { return ostr << value; }
|
||||
std::ostream & operator<< (unsigned long long value) { return ostr << value; }
|
||||
|
||||
std::ostream & operator<< (const std::string & value)
|
||||
{
|
||||
writeEscapedData(value.data(), value.length());
|
||||
return ostr;
|
||||
}
|
||||
|
||||
|
||||
std::ostream & operator<< (const char * value)
|
||||
{
|
||||
while (const char * it = std::strpbrk(value, "\t\n\\"))
|
||||
{
|
||||
ostr.write(value, it - value);
|
||||
switch (*it)
|
||||
{
|
||||
case '\t':
|
||||
ostr.write("\\t", 2);
|
||||
break;
|
||||
case '\n':
|
||||
ostr.write("\\n", 2);
|
||||
break;
|
||||
case '\\':
|
||||
ostr.write("\\\\", 2);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
value = it + 1;
|
||||
}
|
||||
return ostr << value;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
void writeEscapedData(const char * data, size_t length)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
size_t remaining_length = std::strlen(data);
|
||||
(*this) << data;
|
||||
if (i + remaining_length == length)
|
||||
break;
|
||||
|
||||
ostr.write("\\0", 2);
|
||||
i += remaining_length + 1;
|
||||
data += remaining_length + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline EscapeManipResult operator<< (std::ostream & ostr, escape_enum manip)
|
||||
{
|
||||
return EscapeManipResult(ostr);
|
||||
}
|
||||
|
||||
|
||||
struct QuoteManipResult
|
||||
{
|
||||
public:
|
||||
std::ostream & ostr;
|
||||
|
||||
QuoteManipResult(std::ostream & ostr_) : ostr(ostr_) {}
|
||||
|
||||
std::ostream & operator<< (bool value) { return ostr << value; }
|
||||
std::ostream & operator<< (char value) { return ostr << value; }
|
||||
std::ostream & operator<< (unsigned char value) { return ostr << value; }
|
||||
std::ostream & operator<< (signed char value) { return ostr << value; }
|
||||
std::ostream & operator<< (short value) { return ostr << value; }
|
||||
std::ostream & operator<< (unsigned short value) { return ostr << value; }
|
||||
std::ostream & operator<< (int value) { return ostr << value; }
|
||||
std::ostream & operator<< (unsigned int value) { return ostr << value; }
|
||||
std::ostream & operator<< (long value) { return ostr << value; }
|
||||
std::ostream & operator<< (unsigned long value) { return ostr << value; }
|
||||
std::ostream & operator<< (float value) { return ostr << value; }
|
||||
std::ostream & operator<< (double value) { return ostr << value; }
|
||||
std::ostream & operator<< (long long value) { return ostr << value; }
|
||||
std::ostream & operator<< (unsigned long long value) { return ostr << value; }
|
||||
|
||||
std::ostream & operator<< (const std::string & value)
|
||||
{
|
||||
ostr.put('\'');
|
||||
writeEscapedData(value.data(), value.length());
|
||||
ostr.put('\'');
|
||||
|
||||
return ostr;
|
||||
}
|
||||
|
||||
|
||||
std::ostream & operator<< (const char * value)
|
||||
{
|
||||
ostr.put('\'');
|
||||
writeEscapedCString(value);
|
||||
ostr.put('\'');
|
||||
return ostr;
|
||||
}
|
||||
|
||||
|
||||
/* template <typename T1, typename T2>
|
||||
std::ostream & operator<< (const std::pair<T1, T2> & pair)
|
||||
{
|
||||
return ostr << quote << pair.first
|
||||
<< ',' << quote << pair.second;
|
||||
}
|
||||
|
||||
|
||||
template <typename T1, typename T2, typename T3>
|
||||
std::ostream & operator<< (const Poco::Tuple<T1, T2, T3> & tuple)
|
||||
{
|
||||
return ostr << quote << tuple.template get<0>()
|
||||
<< ',' << quote << tuple.template get<1>()
|
||||
<< ',' << quote << tuple.template get<2>();
|
||||
}*/
|
||||
|
||||
private:
|
||||
|
||||
void writeEscapedCString(const char * value)
|
||||
{
|
||||
while (const char * it = std::strpbrk(value, "'\\\""))
|
||||
{
|
||||
ostr.write(value, it - value);
|
||||
switch (*it)
|
||||
{
|
||||
case '"':
|
||||
ostr.write("\\\"", 2);
|
||||
break;
|
||||
case '\'':
|
||||
ostr.write("\\'", 2);
|
||||
break;
|
||||
case '\\':
|
||||
ostr.write("\\\\", 2);
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
value = it + 1;
|
||||
}
|
||||
ostr << value;
|
||||
}
|
||||
|
||||
|
||||
void writeEscapedData(const char * data, size_t length)
|
||||
{
|
||||
size_t i = 0;
|
||||
|
||||
while (true)
|
||||
{
|
||||
size_t remaining_length = std::strlen(data);
|
||||
writeEscapedCString(data);
|
||||
if (i + remaining_length == length)
|
||||
break;
|
||||
|
||||
ostr.write("\\0", 2);
|
||||
i += remaining_length + 1;
|
||||
data += remaining_length + 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
inline QuoteManipResult operator<< (std::ostream & ostr, quote_enum manip)
|
||||
{
|
||||
return QuoteManipResult(ostr);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
345
libs/libmysqlxx/include/mysqlxx/Pool.h
Normal file
345
libs/libmysqlxx/include/mysqlxx/Pool.h
Normal file
@ -0,0 +1,345 @@
|
||||
#ifndef MYSQLXX_POOL_H
|
||||
#define MYSQLXX_POOL_H
|
||||
|
||||
#include <list>
|
||||
|
||||
#include <mysql/mysqld_error.h>
|
||||
|
||||
#include <Poco/Util/Application.h>
|
||||
#include <Poco/Util/LayeredConfiguration.h>
|
||||
#include <Poco/NumberFormatter.h>
|
||||
#include <Poco/Mutex.h>
|
||||
#include <Poco/Exception.h>
|
||||
#include <Poco/SharedPtr.h>
|
||||
|
||||
#include <Yandex/logger_useful.h>
|
||||
#include <Yandex/daemon.h>
|
||||
|
||||
#include <Yandex/daemon.h>
|
||||
|
||||
#include <mysqlxx/Connection.h>
|
||||
|
||||
|
||||
namespace mysqlxx
|
||||
{
|
||||
|
||||
/** @brief Пул соединений с MySQL. */
|
||||
class Pool
|
||||
{
|
||||
protected:
|
||||
/** @brief Информация о соединении. */
|
||||
struct Connection
|
||||
{
|
||||
/** @brief Конструктор. */
|
||||
Connection()
|
||||
: RefCount(0)
|
||||
{
|
||||
}
|
||||
|
||||
mysqlxx::Connection Conn;
|
||||
int RefCount;
|
||||
};
|
||||
|
||||
public:
|
||||
/** @brief Количество соединений с MySQL, создаваемых при запуске. */
|
||||
static const int Std_DefaultConnections;
|
||||
/** @brief Максимально возможное количество соедиений. */
|
||||
static const int Std_MaxConnections;
|
||||
/** @brief Время, в секундах, сколько "спать", если не можем подключиться. */
|
||||
static const int SleepOnConnectFail;
|
||||
|
||||
/** @brief Соединение с базой данных. */
|
||||
class Entry
|
||||
{
|
||||
public:
|
||||
/** @brief Конструктор по-умолчанию. */
|
||||
Entry()
|
||||
: Data(NULL), pool(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief Конструктор копирования. */
|
||||
Entry(const Entry & src)
|
||||
: Data(src.Data), pool(src.pool)
|
||||
{
|
||||
if (Data)
|
||||
Data->RefCount++;
|
||||
}
|
||||
|
||||
/** @brief Деструктор. */
|
||||
virtual ~Entry()
|
||||
{
|
||||
if (Data)
|
||||
Data->RefCount--;
|
||||
}
|
||||
|
||||
/** @brief Оператор присваивания. */
|
||||
Entry & operator= (const Entry & src)
|
||||
{
|
||||
pool = src.pool;
|
||||
if (Data)
|
||||
Data->RefCount--;
|
||||
Data = src.Data;
|
||||
if (Data)
|
||||
Data->RefCount++;
|
||||
return * this;
|
||||
}
|
||||
|
||||
/** @brief Оператор доступа к вложенному объекту. */
|
||||
operator mysqlxx::Connection & ()
|
||||
{
|
||||
if (Data == NULL)
|
||||
throw Poco::RuntimeException("Tried to access NULL database connection.");
|
||||
ForceConnected();
|
||||
return Data->Conn;
|
||||
}
|
||||
|
||||
/** @brief Оператор доступа к вложенному объекту. */
|
||||
operator const mysqlxx::Connection & () const
|
||||
{
|
||||
if (Data == NULL)
|
||||
throw Poco::RuntimeException("Tried to access NULL database connection.");
|
||||
ForceConnected();
|
||||
return Data->Conn;
|
||||
}
|
||||
|
||||
/** @brief Оператор доступа к вложенному объекту. */
|
||||
const mysqlxx::Connection * operator->() const
|
||||
{
|
||||
if (Data == NULL)
|
||||
throw Poco::RuntimeException("Tried to access NULL database connection.");
|
||||
ForceConnected();
|
||||
return &Data->Conn;
|
||||
}
|
||||
|
||||
/** @brief Оператор доступа к вложенному объекту. */
|
||||
mysqlxx::Connection * operator->()
|
||||
{
|
||||
if (Data == NULL)
|
||||
throw Poco::RuntimeException("Tried to access NULL database connection.");
|
||||
ForceConnected();
|
||||
return &Data->Conn;
|
||||
}
|
||||
|
||||
/** @brief Конструктор */
|
||||
Entry(Pool::Connection * Conn, Pool * p)
|
||||
: Data(Conn), pool(p)
|
||||
{
|
||||
if (Data)
|
||||
Data->RefCount++;
|
||||
}
|
||||
|
||||
friend class Pool;
|
||||
|
||||
private:
|
||||
/** @brief Указатель на соединение. */
|
||||
Connection * Data;
|
||||
/** @brief Указатель на пул, которому мы принадлежим. */
|
||||
Pool * pool;
|
||||
|
||||
/** @brief Переподключается к базе данных в случае необходимости. */
|
||||
void ForceConnected() const
|
||||
{
|
||||
Poco::Util::Application & app = Poco::Util::Application::instance();
|
||||
|
||||
if (Data->Conn.ping())
|
||||
return;
|
||||
|
||||
bool first = true;
|
||||
do
|
||||
{
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
::sleep(5);
|
||||
|
||||
app.logger().information("MYSQL: Reconnecting to " + pool->DBName + "@" +
|
||||
pool->DBHost + ":" + Poco::NumberFormatter::format(pool->DBPort) + " as user " + pool->DBUser);
|
||||
Data->Conn.connect(pool->DBName.c_str(), pool->DBHost.c_str(), pool->DBUser.c_str(),
|
||||
pool->DBPass.c_str(), pool->DBPort);
|
||||
}
|
||||
while (!Data->Conn.ping());
|
||||
|
||||
pool->afterConnect(Data->Conn);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Конструктор.
|
||||
* @param ConfigName Имя параметра в конфигурационном файле.
|
||||
* @param DefConn Количество подключений по-умолчанию
|
||||
* @param MaxConn Максимальное количество подключений
|
||||
* @param AllowMultiQueries Не используется.
|
||||
*/
|
||||
Pool(const std::string & ConfigName, int DefConn = Std_DefaultConnections, int MaxConn = Std_MaxConnections,
|
||||
bool AllowMultiQueries = false, const std::string & InitConnect_ = "")
|
||||
: DefaultConnections(DefConn), MaxConnections(MaxConn), InitConnect(InitConnect_),
|
||||
Initialized(false), CfgName(ConfigName)
|
||||
{
|
||||
}
|
||||
|
||||
/** @brief Деструктор. */
|
||||
~Pool()
|
||||
{
|
||||
Poco::ScopedLock<Poco::FastMutex> Locker(Lock);
|
||||
|
||||
for (ConnList::iterator it = Connections.begin(); it != Connections.end(); it++)
|
||||
delete static_cast<Connection *>(*it);
|
||||
}
|
||||
|
||||
/** @brief Выделяет соединение для работы. */
|
||||
Entry Get()
|
||||
{
|
||||
Poco::ScopedLock<Poco::FastMutex> Locker(Lock);
|
||||
|
||||
Initialize();
|
||||
for (;;)
|
||||
{
|
||||
for (ConnList::iterator it = Connections.begin(); it != Connections.end(); it++)
|
||||
{
|
||||
if ((*it)->RefCount == 0)
|
||||
return Entry(*it, this);
|
||||
}
|
||||
|
||||
if (Connections.size() < (size_t)MaxConnections)
|
||||
{
|
||||
Connection * Conn = AllocConnection();
|
||||
if (Conn)
|
||||
{
|
||||
return Entry(Conn, this);
|
||||
}
|
||||
}
|
||||
|
||||
Lock.unlock();
|
||||
sched_yield();
|
||||
::sleep(SleepOnConnectFail);
|
||||
Lock.lock();
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Возвращает имя базы данных. */
|
||||
const std::string & DatabaseName()
|
||||
{
|
||||
Poco::ScopedLock<Poco::FastMutex> Locker(Lock);
|
||||
|
||||
Initialize();
|
||||
return DBName;
|
||||
}
|
||||
|
||||
protected:
|
||||
/** @brief Количество соединений с MySQL, создаваемых при запуске. */
|
||||
int DefaultConnections;
|
||||
/** @brief Максимально возможное количество соедиений. */
|
||||
int MaxConnections;
|
||||
/** @brief Признак возможности использования множественных запросов. */
|
||||
bool AllowMulti;
|
||||
/** @brief Запрос, выполняющийся сразу после соединения с БД. Пример: "SET NAMES cp1251". */
|
||||
std::string InitConnect;
|
||||
|
||||
private:
|
||||
/** @brief Признак того, что мы инициализированы. */
|
||||
bool Initialized;
|
||||
/** @brief Список соединений. */
|
||||
typedef std::list<Connection *> ConnList;
|
||||
/** @brief Список соединений. */
|
||||
ConnList Connections;
|
||||
/** @brief Замок для доступа к списку соединений. */
|
||||
Poco::FastMutex Lock;
|
||||
/** @brief Имя раздела в конфигурационном файле. */
|
||||
std::string CfgName;
|
||||
/** @brief Имя сервера базы данных. */
|
||||
std::string DBHost;
|
||||
/** @brief Порт сервера базы данных. */
|
||||
int DBPort;
|
||||
/** @brief Имя пользователя базы данных. */
|
||||
std::string DBUser;
|
||||
/** @brief Пароль пользователя базы данных. */
|
||||
std::string DBPass;
|
||||
/** @brief Имя базы данных. */
|
||||
std::string DBName;
|
||||
|
||||
/** @brief Выполняет инициализацию класса, если мы еще не инициализированы. */
|
||||
inline void Initialize()
|
||||
{
|
||||
if (!Initialized)
|
||||
{
|
||||
Poco::Util::Application & app = Poco::Util::Application::instance();
|
||||
Poco::Util::LayeredConfiguration & cfg = app.config();
|
||||
|
||||
DBHost = cfg.getString(CfgName + ".host");
|
||||
DBPort = cfg.getInt(CfgName + ".port");
|
||||
DBUser = cfg.getString(CfgName + ".user");
|
||||
DBPass = cfg.getString(CfgName + ".password");
|
||||
DBName = cfg.getString(CfgName + ".db", "");
|
||||
|
||||
for (int i = 0; i < DefaultConnections; i++)
|
||||
AllocConnection();
|
||||
|
||||
Initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** @brief Создает новое соединение. */
|
||||
Connection * AllocConnection()
|
||||
{
|
||||
Poco::Util::Application & app = Poco::Util::Application::instance();
|
||||
Connection * Conn;
|
||||
|
||||
Conn = new Connection();
|
||||
try
|
||||
{
|
||||
app.logger().information("MYSQL: Connecting to " + DBName + "@" +
|
||||
DBHost + ":" + Poco::NumberFormatter::format(DBPort) + " as user " + DBUser);
|
||||
Conn->Conn.connect(DBName.c_str(), DBHost.c_str(), DBUser.c_str(), DBPass.c_str(), DBPort);
|
||||
}
|
||||
catch (mysqlxx::ConnectionFailed & e)
|
||||
{
|
||||
if (e.errnum() == ER_ACCESS_DENIED_ERROR
|
||||
|| e.errnum() == ER_DBACCESS_DENIED_ERROR
|
||||
|| e.errnum() == ER_BAD_DB_ERROR)
|
||||
{
|
||||
app.logger().error(e.what());
|
||||
throw;
|
||||
}
|
||||
else
|
||||
{
|
||||
app.logger().error(e.what());
|
||||
delete Conn;
|
||||
|
||||
if (Daemon::instance().isCancelled())
|
||||
throw Poco::Exception("Daemon is cancelled while trying to connect to MySQL server.");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
afterConnect(Conn->Conn);
|
||||
Connections.push_back(Conn);
|
||||
return Conn;
|
||||
}
|
||||
|
||||
|
||||
/** @brief Действия, выполняемые после соединения. */
|
||||
void afterConnect(mysqlxx::Connection & Conn)
|
||||
{
|
||||
Poco::Util::Application & app = Poco::Util::Application::instance();
|
||||
|
||||
/// Всегда устанавливаем кодировку по умолчанию - UTF8!
|
||||
mysqlxx::Query Q = Conn.query();
|
||||
Q << "SET NAMES utf8";
|
||||
Q.execute();
|
||||
|
||||
/// Инициализирующий запрос (например, установка другой кодировки)
|
||||
if (!InitConnect.empty())
|
||||
{
|
||||
mysqlxx::Query Q = Conn.query();
|
||||
Q << InitConnect;
|
||||
app.logger().trace(Q.str());
|
||||
Q.execute();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -21,8 +21,13 @@ public:
|
||||
UseQueryResult use();
|
||||
StoreQueryResult store();
|
||||
|
||||
std::string str()
|
||||
{
|
||||
return query_stream.str();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Query & operator<< (T & x)
|
||||
Query & operator<< (const T & x)
|
||||
{
|
||||
query_stream << x;
|
||||
return *this;
|
||||
|
@ -25,13 +25,13 @@ public:
|
||||
lengths = mysql_fetch_lengths(&res->getRes());
|
||||
}
|
||||
|
||||
String operator[] (int n)
|
||||
String operator[] (int n) const
|
||||
{
|
||||
std::cerr << lengths[0] << std::endl;
|
||||
return String(row[n], lengths[n]);
|
||||
}
|
||||
|
||||
String operator[] (const char * name)
|
||||
String operator[] (const char * name) const
|
||||
{
|
||||
std::cerr << "???" << std::endl;
|
||||
unsigned n = res->getNumFields();
|
||||
@ -44,13 +44,13 @@ public:
|
||||
throw Exception(std::string("Unknown column ") + name);
|
||||
}
|
||||
|
||||
String at(size_t n)
|
||||
String at(size_t n) const
|
||||
{
|
||||
return operator[](n);
|
||||
}
|
||||
|
||||
operator bool() { return row; }
|
||||
bool operator !() { return !row; }
|
||||
operator bool() const { return row; }
|
||||
bool operator !() const { return !row; }
|
||||
|
||||
private:
|
||||
MYSQL_ROW row;
|
||||
|
@ -16,6 +16,8 @@ class StoreQueryResult : public std::vector<Row>, public ResultBase
|
||||
{
|
||||
public:
|
||||
StoreQueryResult(MYSQL_RES & res_, Connection & conn_);
|
||||
|
||||
size_t num_rows() const { return size(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -160,28 +160,33 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
UInt64 getUInt()
|
||||
bool getBool() const
|
||||
{
|
||||
return m_length > 0 && m_data[0] != '0';
|
||||
}
|
||||
|
||||
UInt64 getUInt() const
|
||||
{
|
||||
UInt64 res;
|
||||
readIntText(res, m_data, m_length);
|
||||
return res;
|
||||
}
|
||||
|
||||
Int64 getInt()
|
||||
Int64 getInt() const
|
||||
{
|
||||
Int64 res;
|
||||
readIntText(res, m_data, m_length);
|
||||
return res;
|
||||
}
|
||||
|
||||
double getDouble()
|
||||
double getDouble() const
|
||||
{
|
||||
double res;
|
||||
readFloatText(res, m_data, m_length);
|
||||
return res;
|
||||
}
|
||||
|
||||
time_t getDateTime()
|
||||
time_t getDateTime() const
|
||||
{
|
||||
Yandex::DateLUTSingleton & date_lut = Yandex::DateLUTSingleton::instance();
|
||||
|
||||
@ -206,47 +211,45 @@ public:
|
||||
throw Exception("Cannot parse DateTime: " + getString());
|
||||
}
|
||||
|
||||
std::string getString()
|
||||
std::string getString() const
|
||||
{
|
||||
return std::string(m_data, m_length);
|
||||
}
|
||||
|
||||
operator UInt64()
|
||||
{
|
||||
return getUInt();
|
||||
}
|
||||
template <typename T> T get();
|
||||
|
||||
/* operator Int64()
|
||||
{
|
||||
return checkDateTime() ? getDateTime() : getInt();
|
||||
}
|
||||
|
||||
operator double()
|
||||
{
|
||||
return getDouble();
|
||||
}
|
||||
|
||||
operator std::string()
|
||||
{
|
||||
return getString();
|
||||
}*/
|
||||
|
||||
const char * data() { return m_data; }
|
||||
size_t length() { return m_length; }
|
||||
size_t size() { return m_length; }
|
||||
const char * data() const { return m_data; }
|
||||
size_t length() const { return m_length; }
|
||||
size_t size() const { return m_length; }
|
||||
|
||||
private:
|
||||
const char * m_data;
|
||||
size_t m_length;
|
||||
|
||||
bool checkDateTime()
|
||||
bool checkDateTime() const
|
||||
{
|
||||
return m_length >= 10 && m_data[4] == '-' && m_data[7] == '-';
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
inline std::ostream & operator<< (std::ostream & ostr, String & x)
|
||||
template <> bool String::get() { return getBool(); }
|
||||
template <> char String::get() { return getInt(); }
|
||||
template <> signed char String::get() { return getInt(); }
|
||||
template <> unsigned char String::get() { return getUInt(); }
|
||||
template <> short String::get() { return getInt(); }
|
||||
template <> unsigned short String::get() { return getUInt(); }
|
||||
template <> int String::get() { return getInt(); }
|
||||
template <> unsigned int String::get() { return getUInt(); }
|
||||
template <> long String::get() { return getInt(); }
|
||||
template <> unsigned long String::get() { return getUInt(); }
|
||||
template <> long long String::get() { return getInt(); }
|
||||
template <> unsigned long long String::get() { return getUInt(); }
|
||||
template <> float String::get() { return getDouble(); }
|
||||
template <> double String::get() { return getDouble(); }
|
||||
|
||||
|
||||
inline std::ostream & operator<< (std::ostream & ostr, const String & x)
|
||||
{
|
||||
return ostr.write(x.data(), x.size());
|
||||
}
|
||||
|
47
libs/libmysqlxx/include/mysqlxx/Transaction.h
Normal file
47
libs/libmysqlxx/include/mysqlxx/Transaction.h
Normal file
@ -0,0 +1,47 @@
|
||||
#ifndef MYSQLXX_TRANSACTION_H
|
||||
#define MYSQLXX_TRANSACTION_H
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#include <mysqlxx/Connection.h>
|
||||
|
||||
|
||||
namespace mysqlxx
|
||||
{
|
||||
|
||||
class Transaction : private boost::noncopyable
|
||||
{
|
||||
public:
|
||||
Transaction(Connection & conn_)
|
||||
: conn(conn_), finished(false)
|
||||
{
|
||||
conn.query("START TRANSACTION").execute();
|
||||
}
|
||||
|
||||
virtual ~Transaction()
|
||||
{
|
||||
if (!finished)
|
||||
rollback();
|
||||
}
|
||||
|
||||
void commit()
|
||||
{
|
||||
conn.query("COMMIT").execute();
|
||||
finished = true;
|
||||
}
|
||||
|
||||
void rollback()
|
||||
{
|
||||
conn.query("ROLLBACK").execute();
|
||||
finished = true;
|
||||
}
|
||||
|
||||
private:
|
||||
Connection & conn;
|
||||
bool finished;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
@ -15,6 +15,11 @@ typedef int Int32;
|
||||
typedef unsigned long * MYSQL_LENGTHS;
|
||||
typedef MYSQL_FIELD * MYSQL_FIELDS;
|
||||
|
||||
/// Для совместимости с mysql++
|
||||
typedef time_t sql_datetime;
|
||||
typedef time_t sql_date;
|
||||
typedef char sql_char;
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -2,6 +2,9 @@
|
||||
#define MYSQLXX_H
|
||||
|
||||
#include <mysqlxx/Connection.h>
|
||||
#include <mysqlxx/Transaction.h>
|
||||
#include <mysqlxx/Manip.h>
|
||||
#include <mysqlxx/Pool.h>
|
||||
|
||||
/** mysqlxx - чрезвычайно простая библиотека для замены библиотеки mysql++.
|
||||
*
|
||||
|
@ -1,3 +1,5 @@
|
||||
#include <Poco/Util/Application.h>
|
||||
|
||||
#include <mysqlxx/Connection.h>
|
||||
#include <mysqlxx/Exception.h>
|
||||
|
||||
@ -21,6 +23,20 @@ Connection::Connection(
|
||||
connect(db, server, user, password, port);
|
||||
}
|
||||
|
||||
Connection::Connection(const std::string & config_name)
|
||||
{
|
||||
is_connected = false;
|
||||
Poco::Util::LayeredConfiguration & cfg = Poco::Util::Application::instance().config();
|
||||
|
||||
std::string db = cfg.getString(config_name + ".db");
|
||||
std::string server = cfg.getString(config_name + ".host");
|
||||
std::string user = cfg.getString(config_name + ".user");
|
||||
std::string password = cfg.getString(config_name + ".password");
|
||||
unsigned port = cfg.getInt(config_name + ".port");
|
||||
|
||||
connect(db.c_str(), server.c_str(), user.c_str(), password.c_str(), port);
|
||||
}
|
||||
|
||||
Connection::~Connection()
|
||||
{
|
||||
disconnect();
|
||||
@ -36,10 +52,10 @@ void Connection::connect(const char* db,
|
||||
disconnect();
|
||||
|
||||
if (!mysql_init(&driver))
|
||||
onError(driver);
|
||||
throw ConnectionFailed(mysql_error(&driver), mysql_errno(&driver));
|
||||
|
||||
if (!mysql_real_connect(&driver, server, user, password, db, port, NULL, driver.client_flag))
|
||||
onError(driver);
|
||||
throw ConnectionFailed(mysql_error(&driver), mysql_errno(&driver));
|
||||
|
||||
is_connected = true;
|
||||
}
|
||||
|
@ -6,6 +6,4 @@
|
||||
namespace mysqlxx
|
||||
{
|
||||
|
||||
POCO_IMPLEMENT_EXCEPTION(Exception, Poco::Exception, "Exception");
|
||||
|
||||
}
|
||||
|
@ -24,7 +24,7 @@ void Query::execute()
|
||||
{
|
||||
std::string query_string = query_stream.str();
|
||||
if (mysql_real_query(&conn.getDriver(), query_string.data(), query_string.size()))
|
||||
onError(conn.getDriver());
|
||||
throw BadQuery(mysql_error(&conn.getDriver()), mysql_errno(&conn.getDriver()));
|
||||
}
|
||||
|
||||
UseQueryResult Query::use()
|
||||
|
Loading…
Reference in New Issue
Block a user