Project SkyFire Core
SkyFire 5.4.8 server core API documentation
Loading...
Searching...
No Matches
PreparedStatement.cpp
Go to the documentation of this file.
1/*
2* This file is part of Project SkyFire https://www.projectskyfire.org.
3* See LICENSE.md file for Copyright information
4*/
5
6#include "Log.h"
7#include "MySQLConnection.h"
8#include "PreparedStatement.h"
9
13
15
17{
19
20 uint8 i = 0;
21 for (; i < statement_data.size(); i++)
22 {
23 switch (statement_data[i].type)
24 {
25 case TYPE_BOOL:
26 m_stmt->setBool(i, statement_data[i].data.boolean);
27 break;
28 case TYPE_UI8:
29 m_stmt->setUInt8(i, statement_data[i].data.ui8);
30 break;
31 case TYPE_UI16:
32 m_stmt->setUInt16(i, statement_data[i].data.ui16);
33 break;
34 case TYPE_UI32:
35 m_stmt->setUInt32(i, statement_data[i].data.ui32);
36 break;
37 case TYPE_I8:
38 m_stmt->setInt8(i, statement_data[i].data.i8);
39 break;
40 case TYPE_I16:
41 m_stmt->setInt16(i, statement_data[i].data.i16);
42 break;
43 case TYPE_I32:
44 m_stmt->setInt32(i, statement_data[i].data.i32);
45 break;
46 case TYPE_UI64:
47 m_stmt->setUInt64(i, statement_data[i].data.ui64);
48 break;
49 case TYPE_I64:
50 m_stmt->setInt64(i, statement_data[i].data.i64);
51 break;
52 case TYPE_FLOAT:
53 m_stmt->setFloat(i, statement_data[i].data.f);
54 break;
55 case TYPE_DOUBLE:
56 m_stmt->setDouble(i, statement_data[i].data.d);
57 break;
58 case TYPE_STRING:
59 m_stmt->setBinary(i, statement_data[i].binary, true);
60 break;
61 case TYPE_BINARY:
62 m_stmt->setBinary(i, statement_data[i].binary, false);
63 break;
64 case TYPE_NULL:
65 m_stmt->setNull(i);
66 break;
67 }
68 }
69#ifdef _DEBUG
70 if (i < m_stmt->m_paramCount)
71 SF_LOG_WARN("sql.sql", "[WARNING]: BindParameters() for statement %u did not bind all allocated parameters", m_index);
72#endif
73}
74
75//- Bind to buffer
76void PreparedStatement::setBool(const uint8 index, const bool value)
77{
78 if (index >= statement_data.size())
79 statement_data.resize(index + 1);
80
81 statement_data[index].data.boolean = value;
82 statement_data[index].type = TYPE_BOOL;
83}
84
85void PreparedStatement::setUInt8(const uint8 index, const uint8 value)
86{
87 if (index >= statement_data.size())
88 statement_data.resize(index + 1);
89
90 statement_data[index].data.ui8 = value;
91 statement_data[index].type = TYPE_UI8;
92}
93
94void PreparedStatement::setUInt16(const uint8 index, const uint16 value)
95{
96 if (index >= statement_data.size())
97 statement_data.resize(index + 1);
98
99 statement_data[index].data.ui16 = value;
100 statement_data[index].type = TYPE_UI16;
101}
102
103void PreparedStatement::setUInt32(const uint8 index, const uint32 value)
104{
105 if (index >= statement_data.size())
106 statement_data.resize(index + 1);
107
108 statement_data[index].data.ui32 = value;
109 statement_data[index].type = TYPE_UI32;
110}
111
112void PreparedStatement::setUInt64(const uint8 index, const uint64 value)
113{
114 if (index >= statement_data.size())
115 statement_data.resize(index + 1);
116
117 statement_data[index].data.ui64 = value;
118 statement_data[index].type = TYPE_UI64;
119}
120
121void PreparedStatement::setInt8(const uint8 index, const int8 value)
122{
123 if (index >= statement_data.size())
124 statement_data.resize(index + 1);
125
126 statement_data[index].data.i8 = value;
127 statement_data[index].type = TYPE_I8;
128}
129
130void PreparedStatement::setInt16(const uint8 index, const int16 value)
131{
132 if (index >= statement_data.size())
133 statement_data.resize(index + 1);
134
135 statement_data[index].data.i16 = value;
136 statement_data[index].type = TYPE_I16;
137}
138
139void PreparedStatement::setInt32(const uint8 index, const int32 value)
140{
141 if (index >= statement_data.size())
142 statement_data.resize(index + 1);
143
144 statement_data[index].data.i32 = value;
145 statement_data[index].type = TYPE_I32;
146}
147
148void PreparedStatement::setInt64(const uint8 index, const int64 value)
149{
150 if (index >= statement_data.size())
151 statement_data.resize(index + 1);
152
153 statement_data[index].data.i64 = value;
154 statement_data[index].type = TYPE_I64;
155}
156
157void PreparedStatement::setFloat(const uint8 index, const float value)
158{
159 if (index >= statement_data.size())
160 statement_data.resize(index + 1);
161
162 statement_data[index].data.f = value;
163 statement_data[index].type = TYPE_FLOAT;
164}
165
166void PreparedStatement::setDouble(const uint8 index, const double value)
167{
168 if (index >= statement_data.size())
169 statement_data.resize(index + 1);
170
171 statement_data[index].data.d = value;
172 statement_data[index].type = TYPE_DOUBLE;
173}
174
175void PreparedStatement::setString(const uint8 index, const std::string& value)
176{
177 if (index >= statement_data.size())
178 statement_data.resize(index + 1);
179
180 statement_data[index].binary.resize(value.length() + 1);
181 memcpy(statement_data[index].binary.data(), value.c_str(), value.length() + 1);
182 statement_data[index].type = TYPE_STRING;
183}
184
185void PreparedStatement::setBinary(const uint8 index, const std::vector<uint8>& value)
186{
187 if (index >= statement_data.size())
188 statement_data.resize(index + 1);
189
190 statement_data[index].binary = value;
191 statement_data[index].type = TYPE_BINARY;
192}
193
195{
196 if (index >= statement_data.size())
197 statement_data.resize(index + 1);
198
199 statement_data[index].type = TYPE_NULL;
200}
201
203 m_stmt(NULL),
204 m_Mstmt(stmt),
205 m_bind(NULL)
206{
208 m_paramCount = mysql_stmt_param_count(stmt);
209 m_paramsSet.assign(m_paramCount, false);
210 m_bind = new MYSQL_BIND[m_paramCount];
211 memset(m_bind, 0, sizeof(MYSQL_BIND) * m_paramCount);
212
214 bool bool_tmp = 1;
215 mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &bool_tmp);
216}
217
219{
221 if (m_Mstmt->bind_result_done)
222 {
223 delete[] m_Mstmt->bind->length;
224 delete[] m_Mstmt->bind->is_null;
225 }
226 mysql_stmt_close(m_Mstmt);
227 delete[] m_bind;
228}
229
231{
232 for (uint32 i = 0; i < m_paramCount; ++i)
233 {
234 delete m_bind[i].length;
235 m_bind[i].length = NULL;
236 delete[](char*) m_bind[i].buffer;
237 m_bind[i].buffer = NULL;
238 m_paramsSet[i] = false;
239 }
240}
241
242static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 paramCount)
243{
244 SF_LOG_ERROR("sql.driver", "Attempted to bind parameter %u%s on a PreparedStatement %u (statement has only %u parameters)", uint32(index) + 1, (index == 1 ? "st" : (index == 2 ? "nd" : (index == 3 ? "rd" : "nd"))), stmtIndex, paramCount);
245 return false;
246}
247
248//- Bind on mysql level
250{
252
253 if (m_paramsSet[index])
254 SF_LOG_WARN("sql.sql", "[WARNING] Prepared Statement (id: %u) trying to bind value on already bound index (%u).", m_stmt->m_index, index);
255 return true;
256}
257
258void MySQLPreparedStatement::setBool(const uint8 index, const bool value)
259{
260 setUInt8(index, value ? 1 : 0);
261}
262
263void MySQLPreparedStatement::setUInt8(const uint8 index, const uint8 value)
264{
265 CheckValidIndex(index);
266 m_paramsSet[index] = true;
267 MYSQL_BIND* param = &m_bind[index];
268 setValue(param, MYSQL_TYPE_TINY, &value, sizeof(uint8), true);
269}
270
271void MySQLPreparedStatement::setUInt16(const uint8 index, const uint16 value)
272{
273 CheckValidIndex(index);
274 m_paramsSet[index] = true;
275 MYSQL_BIND* param = &m_bind[index];
276 setValue(param, MYSQL_TYPE_SHORT, &value, sizeof(uint16), true);
277}
278
279void MySQLPreparedStatement::setUInt32(const uint8 index, const uint32 value)
280{
281 CheckValidIndex(index);
282 m_paramsSet[index] = true;
283 MYSQL_BIND* param = &m_bind[index];
284 setValue(param, MYSQL_TYPE_LONG, &value, sizeof(uint32), true);
285}
286
287void MySQLPreparedStatement::setUInt64(const uint8 index, const uint64 value)
288{
289 CheckValidIndex(index);
290 m_paramsSet[index] = true;
291 MYSQL_BIND* param = &m_bind[index];
292 setValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(uint64), true);
293}
294
295void MySQLPreparedStatement::setInt8(const uint8 index, const int8 value)
296{
297 CheckValidIndex(index);
298 m_paramsSet[index] = true;
299 MYSQL_BIND* param = &m_bind[index];
300 setValue(param, MYSQL_TYPE_TINY, &value, sizeof(int8), false);
301}
302
303void MySQLPreparedStatement::setInt16(const uint8 index, const int16 value)
304{
305 CheckValidIndex(index);
306 m_paramsSet[index] = true;
307 MYSQL_BIND* param = &m_bind[index];
308 setValue(param, MYSQL_TYPE_SHORT, &value, sizeof(int16), false);
309}
310
311void MySQLPreparedStatement::setInt32(const uint8 index, const int32 value)
312{
313 CheckValidIndex(index);
314 m_paramsSet[index] = true;
315 MYSQL_BIND* param = &m_bind[index];
316 setValue(param, MYSQL_TYPE_LONG, &value, sizeof(int32), false);
317}
318
319void MySQLPreparedStatement::setInt64(const uint8 index, const int64 value)
320{
321 CheckValidIndex(index);
322 m_paramsSet[index] = true;
323 MYSQL_BIND* param = &m_bind[index];
324 setValue(param, MYSQL_TYPE_LONGLONG, &value, sizeof(int64), false);
325}
326
327void MySQLPreparedStatement::setFloat(const uint8 index, const float value)
328{
329 CheckValidIndex(index);
330 m_paramsSet[index] = true;
331 MYSQL_BIND* param = &m_bind[index];
332 setValue(param, MYSQL_TYPE_FLOAT, &value, sizeof(float), (value > 0.0f));
333}
334
335void MySQLPreparedStatement::setDouble(const uint8 index, const double value)
336{
337 CheckValidIndex(index);
338 m_paramsSet[index] = true;
339 MYSQL_BIND* param = &m_bind[index];
340 setValue(param, MYSQL_TYPE_DOUBLE, &value, sizeof(double), (value > 0.0f));
341}
342
343void MySQLPreparedStatement::setBinary(const uint8 index, const std::vector<uint8>& value, bool isString)
344{
345 CheckValidIndex(index);
346 m_paramsSet[index] = true;
347 MYSQL_BIND* param = &m_bind[index];
348 uint32 len = uint32(value.size());
349 param->buffer_type = MYSQL_TYPE_BLOB;
350 delete[] static_cast<char*>(param->buffer);
351 param->buffer = new char[len];
352 param->buffer_length = len;
353 param->is_null_value = 0;
354 delete param->length;
355 param->length = new unsigned long(len);
356 if (isString)
357 {
358 *param->length -= 1;
359 param->buffer_type = MYSQL_TYPE_VAR_STRING;
360 }
361
362 memcpy(param->buffer, value.data(), len);
363}
364
366{
367 CheckValidIndex(index);
368 m_paramsSet[index] = true;
369 MYSQL_BIND* param = &m_bind[index];
370 param->buffer_type = MYSQL_TYPE_NULL;
371 delete[] static_cast<char*>(param->buffer);
372 param->buffer = NULL;
373 param->buffer_length = 0;
374 param->is_null_value = 1;
375 delete param->length;
376 param->length = NULL;
377}
378
379void MySQLPreparedStatement::setValue(MYSQL_BIND* param, enum_field_types type, const void* value, uint32 len, bool isUnsigned)
380{
381 param->buffer_type = type;
382 delete[] static_cast<char*>(param->buffer);
383 param->buffer = new char[len];
384 param->buffer_length = 0;
385 param->is_null_value = 0;
386 param->length = NULL; // Only != NULL for strings
387 param->is_unsigned = isUnsigned;
388
389 memcpy(param->buffer, value, len);
390}
391
392std::string MySQLPreparedStatement::getQueryString(std::string const& sqlPattern) const
393{
394 std::string queryString = sqlPattern;
395
396 size_t pos = 0;
397 for (uint32 i = 0; i < m_stmt->statement_data.size(); i++)
398 {
399 pos = queryString.find('?', pos);
400 std::stringstream ss;
401
402 switch (m_stmt->statement_data[i].type)
403 {
404 case TYPE_BOOL:
405 ss << uint16(m_stmt->statement_data[i].data.boolean);
406 break;
407 case TYPE_UI8:
408 ss << uint16(m_stmt->statement_data[i].data.ui8); // stringstream will append a character with that code instead of numeric representation
409 break;
410 case TYPE_UI16:
411 ss << m_stmt->statement_data[i].data.ui16;
412 break;
413 case TYPE_UI32:
414 ss << m_stmt->statement_data[i].data.ui32;
415 break;
416 case TYPE_I8:
417 ss << int16(m_stmt->statement_data[i].data.i8); // stringstream will append a character with that code instead of numeric representation
418 break;
419 case TYPE_I16:
420 ss << m_stmt->statement_data[i].data.i16;
421 break;
422 case TYPE_I32:
423 ss << m_stmt->statement_data[i].data.i32;
424 break;
425 case TYPE_UI64:
426 ss << m_stmt->statement_data[i].data.ui64;
427 break;
428 case TYPE_I64:
429 ss << m_stmt->statement_data[i].data.i64;
430 break;
431 case TYPE_FLOAT:
432 ss << m_stmt->statement_data[i].data.f;
433 break;
434 case TYPE_DOUBLE:
435 ss << m_stmt->statement_data[i].data.d;
436 break;
437 case TYPE_STRING:
438 ss << '\'' << (char const*)m_stmt->statement_data[i].binary.data() << '\'';
439 break;
440 case TYPE_BINARY:
441 ss << "BINARY";
442 break;
443 case TYPE_NULL:
444 ss << "NULL";
445 break;
446 }
447
448 std::string replaceStr = ss.str();
449 queryString.replace(pos, 1, replaceStr);
450 pos += replaceStr.length();
451 }
452
453 return queryString;
454}
455
456//- Execution
460
465
466
471
473{
474 if (m_has_result)
475 {
476 PreparedResultSet* result = m_conn->Query(m_stmt);
477 if (!result || !result->GetRowCount())
478 {
479 delete result;
480 m_result.set(PreparedQueryResult(NULL));
481 return false;
482 }
483 m_result.set(PreparedQueryResult(result));
484 return true;
485 }
486
487 return m_conn->Execute(m_stmt);
488}
std::int32_t int32
Definition Define.h:73
std::uint8_t uint8
Definition Define.h:79
std::uint32_t uint32
Definition Define.h:77
std::int8_t int8
Definition Define.h:75
std::uint64_t uint64
Definition Define.h:76
std::int64_t int64
Definition Define.h:72
std::uint16_t uint16
Definition Define.h:78
std::int16_t int16
Definition Define.h:74
#define ASSERT
Definition Errors.h:29
#define SF_LOG_WARN(filterType__,...)
Definition Log.h:140
#define SF_LOG_ERROR(filterType__,...)
Definition Log.h:143
static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 paramCount)
Skyfire::Future< PreparedQueryResult > PreparedQueryResultFuture
@ TYPE_DOUBLE
@ TYPE_NULL
@ TYPE_FLOAT
@ TYPE_BOOL
@ TYPE_UI32
@ TYPE_I16
@ TYPE_I64
@ TYPE_BINARY
@ TYPE_I32
@ TYPE_I8
@ TYPE_UI8
@ TYPE_STRING
@ TYPE_UI16
@ TYPE_UI64
Skyfire::AutoPtr< PreparedResultSet, Skyfire::Mutex > PreparedQueryResult
Definition QueryResult.h:94
void setUInt32(const uint8 index, const uint32 value)
void setBool(const uint8 index, const bool value)
void setNull(const uint8 index)
MySQLPreparedStatement(MYSQL_STMT *stmt)
void setInt64(const uint8 index, const int64 value)
void setDouble(const uint8 index, const double value)
void setInt8(const uint8 index, const int8 value)
PreparedStatement * m_stmt
std::string getQueryString(std::string const &sqlPattern) const
void setUInt64(const uint8 index, const uint64 value)
void setUInt16(const uint8 index, const uint16 value)
bool CheckValidIndex(uint8 index)
void setInt32(const uint8 index, const int32 value)
void setUInt8(const uint8 index, const uint8 value)
void setValue(MYSQL_BIND *param, enum_field_types type, const void *value, uint32 len, bool isUnsigned)
void setFloat(const uint8 index, const float value)
void setInt16(const uint8 index, const int16 value)
void setBinary(const uint8 index, const std::vector< uint8 > &value, bool isString)
std::vector< bool > m_paramsSet
uint64 GetRowCount() const
Definition QueryResult.h:57
void setBool(const uint8 index, const bool value)
void setFloat(const uint8 index, const float value)
void setString(const uint8 index, const std::string &value)
void setInt64(const uint8 index, const int64 value)
MySQLPreparedStatement * m_stmt
void setUInt16(const uint8 index, const uint16 value)
PreparedStatement(uint32 index)
void setUInt64(const uint8 index, const uint64 value)
void setBinary(const uint8 index, const std::vector< uint8 > &value)
void setNull(const uint8 index)
void setInt8(const uint8 index, const int8 value)
void setUInt32(const uint8 index, const uint32 value)
std::vector< PreparedStatementData > statement_data
void setInt16(const uint8 index, const int16 value)
void setDouble(const uint8 index, const double value)
void setUInt8(const uint8 index, const uint8 value)
void setInt32(const uint8 index, const int32 value)
PreparedStatementTask(PreparedStatement *stmt)
PreparedQueryResultFuture m_result
PreparedStatement * m_stmt
MySQLConnection * m_conn