TrinityCore
MySQLPreparedStatement.cpp
Go to the documentation of this file.
1/*
2 * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU General Public License as published by the
6 * Free Software Foundation; either version 2 of the License, or (at your
7 * option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 *
14 * You should have received a copy of the GNU General Public License along
15 * with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
19#include "Errors.h"
20#include "Log.h"
21#include "MySQLHacks.h"
22#include "PreparedStatement.h"
23#include <cstring>
24
25template<typename T>
26struct MySQLType { };
27
28template<> struct MySQLType<uint8> : std::integral_constant<enum_field_types, MYSQL_TYPE_TINY> { };
29template<> struct MySQLType<uint16> : std::integral_constant<enum_field_types, MYSQL_TYPE_SHORT> { };
30template<> struct MySQLType<uint32> : std::integral_constant<enum_field_types, MYSQL_TYPE_LONG> { };
31template<> struct MySQLType<uint64> : std::integral_constant<enum_field_types, MYSQL_TYPE_LONGLONG> { };
32template<> struct MySQLType<int8> : std::integral_constant<enum_field_types, MYSQL_TYPE_TINY> { };
33template<> struct MySQLType<int16> : std::integral_constant<enum_field_types, MYSQL_TYPE_SHORT> { };
34template<> struct MySQLType<int32> : std::integral_constant<enum_field_types, MYSQL_TYPE_LONG> { };
35template<> struct MySQLType<int64> : std::integral_constant<enum_field_types, MYSQL_TYPE_LONGLONG> { };
36template<> struct MySQLType<float> : std::integral_constant<enum_field_types, MYSQL_TYPE_FLOAT> { };
37template<> struct MySQLType<double> : std::integral_constant<enum_field_types, MYSQL_TYPE_DOUBLE> { };
38
40 m_stmt(nullptr), m_Mstmt(stmt), m_bind(nullptr), m_queryString(std::move(queryString))
41{
43 m_paramCount = mysql_stmt_param_count(stmt);
44 m_paramsSet.assign(m_paramCount, false);
46 memset(m_bind, 0, sizeof(MySQLBind) * m_paramCount);
47
49 MySQLBool bool_tmp = MySQLBool(1);
50 mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &bool_tmp);
51}
52
54{
56 if (m_Mstmt->bind_result_done)
57 {
58 delete[] m_Mstmt->bind->length;
59 delete[] m_Mstmt->bind->is_null;
60 }
61 mysql_stmt_close(m_Mstmt);
62 delete[] m_bind;
63}
64
66{
67 m_stmt = stmt; // Cross reference them for debug output
68
69 uint8 pos = 0;
70 for (PreparedStatementData const& data : stmt->GetParameters())
71 {
72 std::visit([&](auto&& param)
73 {
74 SetParameter(pos, param);
75 }, data.data);
76 ++pos;
77 }
78#ifdef _DEBUG
79 if (pos < m_paramCount)
80 TC_LOG_WARN("sql.sql", "[WARNING]: BindParameters() for statement {} did not bind all allocated parameters", stmt->GetIndex());
81#endif
82}
83
85{
86 for (uint32 i=0; i < m_paramCount; ++i)
87 {
88 delete m_bind[i].length;
89 m_bind[i].length = nullptr;
90 delete[] (char*) m_bind[i].buffer;
91 m_bind[i].buffer = nullptr;
92 m_paramsSet[i] = false;
93 }
94}
95
96static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 paramCount)
97{
98 TC_LOG_ERROR("sql.driver", "Attempted to bind parameter {}{} on a PreparedStatement {} (statement has only {} parameters)", uint32(index) + 1, (index == 1 ? "st" : (index == 2 ? "nd" : (index == 3 ? "rd" : "nd"))), stmtIndex, paramCount);
99 return false;
100}
101
102//- Bind on mysql level
104{
106
107 if (m_paramsSet[index])
108 TC_LOG_ERROR("sql.sql", "[ERROR] Prepared Statement (id: {}) trying to bind value on already bound index ({}).", m_stmt->GetIndex(), index);
109}
110
112{
113 AssertValidIndex(index);
114 m_paramsSet[index] = true;
115 MYSQL_BIND* param = &m_bind[index];
116 param->buffer_type = MYSQL_TYPE_NULL;
117 delete[] static_cast<char *>(param->buffer);
118 param->buffer = nullptr;
119 param->buffer_length = 0;
120 param->is_null_value = 1;
121 delete param->length;
122 param->length = nullptr;
123}
124
126{
127 SetParameter(index, uint8(value ? 1 : 0));
128}
129
130template<typename T>
132{
133 AssertValidIndex(index);
134 m_paramsSet[index] = true;
135 MYSQL_BIND* param = &m_bind[index];
136 uint32 len = uint32(sizeof(T));
137 param->buffer_type = MySQLType<T>::value;
138 delete[] static_cast<char*>(param->buffer);
139 param->buffer = new char[len];
140 param->buffer_length = 0;
141 param->is_null_value = 0;
142 param->length = nullptr; // Only != NULL for strings
143 param->is_unsigned = std::is_unsigned_v<T>;
144
145 memcpy(param->buffer, &value, len);
146}
147
148void MySQLPreparedStatement::SetParameter(uint8 index, std::string const& value)
149{
150 AssertValidIndex(index);
151 m_paramsSet[index] = true;
152 MYSQL_BIND* param = &m_bind[index];
153 uint32 len = uint32(value.size());
154 param->buffer_type = MYSQL_TYPE_VAR_STRING;
155 delete [] static_cast<char*>(param->buffer);
156 param->buffer = new char[len];
157 param->buffer_length = len;
158 param->is_null_value = 0;
159 delete param->length;
160 param->length = new unsigned long(len);
161
162 memcpy(param->buffer, value.c_str(), len);
163}
164
165void MySQLPreparedStatement::SetParameter(uint8 index, std::vector<uint8> const& value)
166{
167 AssertValidIndex(index);
168 m_paramsSet[index] = true;
169 MYSQL_BIND* param = &m_bind[index];
170 uint32 len = uint32(value.size());
171 param->buffer_type = MYSQL_TYPE_BLOB;
172 delete [] static_cast<char *>(param->buffer);
173 param->buffer = new char[len];
174 param->buffer_length = len;
175 param->is_null_value = 0;
176 delete param->length;
177 param->length = new unsigned long(len);
178
179 memcpy(param->buffer, value.data(), len);
180}
181
183{
184 std::string queryString(m_queryString);
185
186 size_t pos = 0;
187 for (PreparedStatementData const& data : m_stmt->GetParameters())
188 {
189 pos = queryString.find('?', pos);
190
191 std::string replaceStr = std::visit([&](auto&& data)
192 {
194 }, data.data);
195
196 queryString.replace(pos, 1, replaceStr);
197 pos += replaceStr.length();
198 }
199
200 return queryString;
201}
uint8_t uint8
Definition: Define.h:144
int64_t int64
Definition: Define.h:137
int16_t int16
Definition: Define.h:139
int8_t int8
Definition: Define.h:140
int32_t int32
Definition: Define.h:138
uint64_t uint64
Definition: Define.h:141
uint16_t uint16
Definition: Define.h:143
uint32_t uint32
Definition: Define.h:142
#define ASSERT
Definition: Errors.h:68
#define TC_LOG_WARN(filterType__,...)
Definition: Log.h:162
#define TC_LOG_ERROR(filterType__,...)
Definition: Log.h:165
std::remove_pointer_t< decltype(std::declval< MYSQL_BIND >().is_null)> MySQLBool
Definition: MySQLHacks.h:32
static bool ParamenterIndexAssertFail(uint32 stmtIndex, uint8 index, uint32 paramCount)
PreparedStatementBase * m_stmt
void SetParameter(uint8 index, std::nullptr_t)
std::string getQueryString() const
std::string const m_queryString
void BindParameters(PreparedStatementBase *stmt)
std::vector< bool > m_paramsSet
MySQLPreparedStatement(MySQLStmt *stmt, std::string queryString)
std::vector< PreparedStatementData > const & GetParameters() const
STL namespace.
static std::string ToString(T value)