Skip to content

Commit 9108f03

Browse files
author
Ivan Pizhenko
committed
Added intial support for queries
1 parent 78b76db commit 9108f03

File tree

1 file changed

+152
-12
lines changed

1 file changed

+152
-12
lines changed

src/libmysqlclient_cpp_wrapper.h

Lines changed: 152 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ constexpr int PATCH = 0;
5757
class MySQLClientLibrary;
5858
class MySQLConnection;
5959
class MySQLPreparedStatement;
60+
class MySQLQuery;
6061

6162
class MySQLClientLibrary {
6263
private:
@@ -102,7 +103,8 @@ class MySQLConnection {
102103
private:
103104
MySQLConnection(const std::shared_ptr<MySQLClientLibrary>& library) :
104105
m_library(library),
105-
m_mysql(mysql_init(nullptr))
106+
m_mysql(::mysql_init(nullptr)),
107+
m_hasActiveQuery(false)
106108
{
107109
if (!m_mysql) {
108110
throw std::runtime_error("failed to initialize connection object");
@@ -120,7 +122,7 @@ class MySQLConnection {
120122
~MySQLConnection()
121123
{
122124
if (m_mysql) {
123-
mysql_close(m_mysql);
125+
::mysql_close(m_mysql);
124126
}
125127
}
126128

@@ -137,7 +139,7 @@ class MySQLConnection {
137139
void connect(const std::string& host, const unsigned port, const std::string& database,
138140
const std::string& user, const char* password, unsigned long clientFlags = 0)
139141
{
140-
if (!mysql_real_connect(m_mysql, host.c_str(), user.c_str(), password,
142+
if (!::mysql_real_connect(m_mysql, host.c_str(), user.c_str(), password,
141143
database.c_str(), port, nullptr, clientFlags)) {
142144
throw std::runtime_error("could not connect to database server");
143145
}
@@ -154,12 +156,151 @@ class MySQLConnection {
154156

155157
unsigned long getServerVersion() const noexcept
156158
{
157-
return mysql_get_server_version(m_mysql);
159+
return ::mysql_get_server_version(m_mysql);
160+
}
161+
162+
void setHasActiveQuery(bool hasActiveQuery) noexcept
163+
{
164+
m_hasActiveQuery = hasActiveQuery;
165+
}
166+
167+
bool hasActiveQuery() const noexcept
168+
{
169+
return m_hasActiveQuery;
170+
}
171+
172+
void commit()
173+
{
158174
}
159175

160176
private:
161177
std::shared_ptr<MySQLClientLibrary> m_library;
162178
::MYSQL* m_mysql;
179+
bool m_hasActiveQuery;
180+
};
181+
182+
class MySQLQuery {
183+
private:
184+
MySQLQuery(const std::shared_ptr<MySQLConnection>& conn, const char* sql, std::size_t length) :
185+
m_conn(conn),
186+
m_errorCode(0)
187+
{
188+
if (conn->hasActiveQuery()) {
189+
throw std::logic_error("some query is already running");
190+
}
191+
192+
MYSQL* mysql = (MYSQL*)*conn;
193+
194+
m_errorCode = ::mysql_real_query(mysql, sql, static_cast<unsigned long>(length));
195+
if (m_errorCode) {
196+
throw std::runtime_error("failed to execute MySQL query");
197+
}
198+
199+
conn->setHasActiveQuery(true);
200+
}
201+
202+
public:
203+
static std::shared_ptr<MySQLQuery> create(const std::shared_ptr<MySQLConnection>& conn,
204+
const std::string& sql)
205+
{
206+
return std::shared_ptr<MySQLQuery>(new MySQLQuery(conn, sql.c_str(), sql.length()));
207+
}
208+
209+
static std::shared_ptr<MySQLQuery> create(const std::shared_ptr<MySQLConnection>& conn,
210+
const char* sql, std::size_t length)
211+
{
212+
return std::shared_ptr<MySQLQuery>(new MySQLQuery(conn, sql, length));
213+
}
214+
215+
~MySQLQuery() noexcept
216+
{
217+
stop();
218+
}
219+
220+
MySQLQuery(const MySQLQuery&) = delete;
221+
MySQLQuery(MySQLQuery&&) = delete;
222+
MySQLQuery& operator=(const MySQLQuery&) = delete;
223+
MySQLQuery& operator=(MySQLQuery&&) = delete;
224+
225+
unsigned int getFieldCount() const noexcept
226+
{
227+
return mysql_field_count((MYSQL*)*m_conn);
228+
}
229+
230+
bool hasResults() const noexcept
231+
{
232+
return getFieldCount() > 0;
233+
}
234+
235+
unsigned long long getNumberOfAffectedRows() const noexcept
236+
{
237+
return ::mysql_affected_rows((MYSQL*)*m_conn);
238+
}
239+
240+
bool hasMoreResults() const noexcept
241+
{
242+
return ::mysql_more_results((MYSQL*)*m_conn);
243+
}
244+
245+
bool nextResult()
246+
{
247+
const auto result = ::mysql_next_result((MYSQL*)*m_conn);
248+
if (result > 0) {
249+
throw std::runtime_error("failed to fetch next row");
250+
}
251+
return result == 0;
252+
}
253+
254+
bool useResult()
255+
{
256+
m_result = ::mysql_use_result((MYSQL*)*m_conn);
257+
if (m_result == nullptr && ::mysql_errno((MYSQL*)*m_conn) != 0) {
258+
throw std::runtime_error("failed to fetch first row of result");
259+
}
260+
}
261+
262+
MYSQL_ROW fetchRow()
263+
{
264+
checkHaveResult();
265+
MYSQL_ROW row = ::mysql_fetch_row(m_result);
266+
if (::mysql_errno((MYSQL*)*m_conn) != 0) {
267+
throw std::runtime_error("failed to fetch next row");
268+
}
269+
return row;
270+
}
271+
272+
void stopResult()
273+
{
274+
checkHaveResult();
275+
doStopResult();
276+
}
277+
278+
void stop() noexcept
279+
{
280+
if (m_result) {
281+
doStopResult();
282+
}
283+
m_conn->setHasActiveQuery(false);
284+
}
285+
286+
private:
287+
288+
void checkHaveResult() const
289+
{
290+
if (!m_result) {
291+
throw std::logic_error("there is no active result");
292+
}
293+
}
294+
295+
void doStopResult()
296+
{
297+
::mysql_free_result(m_result);
298+
m_result = nullptr;
299+
}
300+
301+
std::shared_ptr<MySQLConnection> m_conn;
302+
int m_errorCode;
303+
MYSQL_RES* m_result;
163304
};
164305

165306
class MySQLPreparedStatement {
@@ -178,8 +319,7 @@ class MySQLPreparedStatement {
178319

179320
public:
180321

181-
static std::shared_ptr<MySQLPreparedStatement> create(
182-
const std::shared_ptr<MySQLConnection>& conn)
322+
static std::shared_ptr<MySQLPreparedStatement> create(const std::shared_ptr<MySQLConnection>& conn)
183323
{
184324
return std::shared_ptr<MySQLPreparedStatement>(new MySQLPreparedStatement(conn));
185325
}
@@ -216,7 +356,7 @@ class MySQLPreparedStatement {
216356
if (len == std::string::npos) {
217357
len = strlen(sql);
218358
}
219-
m_errorCode = mysql_stmt_prepare(m_stmt, sql, static_cast<unsigned long>(len));
359+
m_errorCode = ::mysql_stmt_prepare(m_stmt, sql, static_cast<unsigned long>(len));
220360
if (m_errorCode != 0) {
221361
std::ostringstream err;
222362
err << "failed to prepare prepared statement: "
@@ -286,7 +426,7 @@ class MySQLPreparedStatement {
286426
if (m_parameters.empty()) {
287427
throw std::logic_error("there are no parameters");
288428
}
289-
m_errorCode = mysql_stmt_bind_param(m_stmt, &m_parameters[0]);
429+
m_errorCode = ::mysql_stmt_bind_param(m_stmt, &m_parameters[0]);
290430
if (m_errorCode != 0) {
291431
std::ostringstream err;
292432
err << "failed to bind parameters prepared statement: "
@@ -351,7 +491,7 @@ class MySQLPreparedStatement {
351491
if (m_results.empty()) {
352492
throw std::logic_error("there are no results");
353493
}
354-
m_errorCode = mysql_stmt_bind_result(m_stmt, &m_results[0]);
494+
m_errorCode = ::mysql_stmt_bind_result(m_stmt, &m_results[0]);
355495
if (m_errorCode != 0) {
356496
std::ostringstream err;
357497
err << "failed to bind results prepared statement: "
@@ -362,7 +502,7 @@ class MySQLPreparedStatement {
362502

363503
void execute()
364504
{
365-
m_errorCode = mysql_stmt_execute(m_stmt);
505+
m_errorCode = ::mysql_stmt_execute(m_stmt);
366506
if (m_errorCode != 0) {
367507
std::ostringstream err;
368508
err << "failed to execute prepared statement: "
@@ -373,7 +513,7 @@ class MySQLPreparedStatement {
373513

374514
bool fetch()
375515
{
376-
const int res = mysql_stmt_fetch(m_stmt);
516+
const int res = ::mysql_stmt_fetch(m_stmt);
377517
switch (res) {
378518
case 0: return true;
379519
case MYSQL_NO_DATA: return false;
@@ -383,7 +523,7 @@ class MySQLPreparedStatement {
383523

384524
void stop()
385525
{
386-
if (mysql_stmt_free_result(m_stmt)) {
526+
if (::mysql_stmt_free_result(m_stmt)) {
387527
throw std::runtime_error("failed to stop prepared statement");
388528
}
389529
}

0 commit comments

Comments
 (0)