KDb

MysqlPreparedStatement.cpp
1/* This file is part of the KDE project
2 Copyright (C) 2006-2012 Jarosław Staniek <staniek@kde.org>
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Library General Public
6 License as published by the Free Software Foundation; either
7 version 2 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Library General Public License for more details.
13
14 You should have received a copy of the GNU Library General Public License
15 along with this program; see the file COPYING. If not, write to
16 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18*/
19
20#include "MysqlPreparedStatement.h"
21#include "KDbConnection.h"
22
23//#include <mysql/errmsg.h>
24// For example prepared MySQL statement code see:
25// https://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-execute.html
26
27MysqlPreparedStatement::MysqlPreparedStatement(MysqlConnectionInternal* conn)
29 , MysqlConnectionInternal(conn->connection)
30#ifdef KDB_USE_MYSQL_STMT
31 , m_statement(0)
32 , m_mysqlBind(0)
33#endif
34 , m_resetRequired(false)
35{
36// mysqlDebug();
37 mysql_owned = false;
38 mysql = conn->mysql;
39 if (!init()) {
40 done();
41 }
42}
43
44bool MysqlPreparedStatement::init()
45{
46#ifdef KDB_USE_MYSQL_STMT
47 m_statement = mysql_stmt_init(mysql);
48 if (!m_statement) {
49//! @todo err 'out of memory'
50 return false;
51 }
52 res = mysql_stmt_prepare(m_statement,
53 (const char*)m_tempStatementString, m_tempStatementString.length());
54 if (0 != res) {
55//! @todo use mysql_stmt_error(stmt); to show error
56 return false;
57 }
58
59 m_realParamCount = mysql_stmt_param_count(m_statement);
60 if (m_realParamCount <= 0) {
61//! @todo err
62 return false;
63 }
64 m_mysqlBind = new MYSQL_BIND[ m_realParamCount ];
65 memset(m_mysqlBind, 0, sizeof(MYSQL_BIND)*m_realParamCount); //safe?
66#endif
67 return true;
68}
69
70MysqlPreparedStatement::~MysqlPreparedStatement()
71{
72 done();
73}
74
75void MysqlPreparedStatement::done()
76{
77#ifdef KDB_USE_MYSQL_STMT
78 if (m_statement) {
79//! @todo handle errors of mysql_stmt_close()?
80 mysql_stmt_close(m_statement);
81 m_statement = 0;
82 }
83 delete m_mysqlBind;
84 m_mysqlBind = 0;
85#endif
86}
87
88bool MysqlPreparedStatement::prepare(const KDbEscapedString& sql)
89{
90 Q_UNUSED(sql);
91 return true;
92}
93
94#ifdef KDB_USE_MYSQL_STMT
95#define BIND_NULL { \
96 m_mysqlBind[arg].buffer_type = MYSQL_TYPE_NULL; \
97 m_mysqlBind[arg].buffer = 0; \
98 m_mysqlBind[arg].buffer_length = 0; \
99 m_mysqlBind[arg].is_null = &dummyNull; \
100 m_mysqlBind[arg].length = &str_length; }
101
102bool MysqlPreparedStatement::bindValue(KDbField *field, const QVariant& value, int arg)
103{
104 if (value.isNull()) {
105 // no value to bind or the value is null: bind NULL
106 BIND_NULL;
107 return true;
108 }
109
110 if (field->isTextType()) {
111//! @todo optimize
112 m_stringBuffer[ 1024 ]; ? ? ?
113 char *str = qstrncpy(m_stringBuffer, (const char*)value.toString().toUtf8(), 1024);
114 m_mysqlBind[arg].buffer_type = MYSQL_TYPE_STRING;
115 m_mysqlBind[arg].buffer = m_stringBuffer;
116 m_mysqlBind[arg].is_null = (my_bool*)0;
117 m_mysqlBind[arg].buffer_length = 1024; //?
118 m_mysqlBind[arg].length = &str_length;
119 return true;
120 }
121
122 switch (field->type()) {
123 case KDbField::Byte:
125 case KDbField::Integer: {
126 //! @todo what about unsigned > INT_MAX ?
127 bool ok;
128 const int intValue = value.toInt(&ok);
129 if (ok) {
130 if (field->type() == KDbField::Byte)
131 m_mysqlBind[arg].buffer_type = MYSQL_TYPE_TINY;
132 else if (field->type() == KDbField::ShortInteger)
133 m_mysqlBind[arg].buffer_type = MYSQL_TYPE_SHORT;
134 else if (field->type() == KDbField::Integer)
135 m_mysqlBind[arg].buffer_type = MYSQL_TYPE_LONG;
136
137 m_mysqlBind[arg].is_null = (my_bool*)0;
138 m_mysqlBind[arg].length = 0;
139
140 res = sqlite3_bind_int(prepared_st_handle, arg, intValue);
141 if (SQLITE_OK != res) {
142 //! @todo msg?
143 return false;
144 }
145 } else
146 BIND_NULL;
147 break;
148 }
149 case KDbField::Float:
150 case KDbField::Double:
151 res = sqlite3_bind_double(prepared_st_handle, arg, value.toDouble());
152 if (SQLITE_OK != res) {
153 //! @todo msg?
154 return false;
155 }
156 break;
158 //! @todo what about unsigned > LLONG_MAX ?
159 bool ok;
160 qint64 int64Value = value.toLongLong(&ok);
161 if (ok) {
162 res = sqlite3_bind_int64(prepared_st_handle, arg, value);
163 if (SQLITE_OK != res) {
164 //! @todo msg?
165 return false;
166 }
167 } else {
168 res = sqlite3_bind_null(prepared_st_handle, arg);
169 if (SQLITE_OK != res) {
170 //! @todo msg?
171 return false;
172 }
173 }
174 break;
175 }
177 res = sqlite3_bind_text(prepared_st_handle, arg,
178 QString::number(value.toBool() ? 1 : 0).toLatin1(),
179 1, SQLITE_TRANSIENT /*??*/);
180 if (SQLITE_OK != res) {
181 //! @todo msg?
182 return false;
183 }
184 break;
185 case KDbField::Time:
186 res = sqlite3_bind_text(prepared_st_handle, arg,
188 sizeof("HH:MM:SS"), SQLITE_TRANSIENT /*??*/);
189 if (SQLITE_OK != res) {
190 //! @todo msg?
191 return false;
192 }
193 break;
194 case KDbField::Date:
195 res = sqlite3_bind_text(prepared_st_handle, arg,
197 sizeof("YYYY-MM-DD"), SQLITE_TRANSIENT /*??*/);
198 if (SQLITE_OK != res) {
199 //! @todo msg?
200 return false;
201 }
202 break;
203 case KDbField::DateTime:
204 res = sqlite3_bind_text(prepared_st_handle, arg,
206 sizeof("YYYY-MM-DDTHH:MM:SS"), SQLITE_TRANSIENT /*??*/);
207 if (SQLITE_OK != res) {
208 //! @todo msg?
209 return false;
210 }
211 break;
212 case KDbField::BLOB: {
213 const QByteArray byteArray(value.toByteArray());
214 res = sqlite3_bind_blob(prepared_st_handle, arg,
215 (const char*)byteArray, byteArray.size(), SQLITE_TRANSIENT /*??*/);
216 if (SQLITE_OK != res) {
217 //! @todo msg?
218 return false;
219 }
220 break;
221 }
222 default:
223 mysqlWarning() << "unsupported field type:"
224 << field->type() << "- NULL value bound to column #" << arg;
225 res = sqlite3_bind_null(prepared_st_handle, arg);
226 if (SQLITE_OK != res) {
227 //! @todo msg?
228 return false;
229 }
230 } //switch
231 return true;
232}
233#endif
234
235QSharedPointer<KDbSqlResult> MysqlPreparedStatement::execute(KDbPreparedStatement::Type type,
236 const KDbField::List &selectFieldList,
237 KDbFieldList *insertFieldList,
238 const KDbPreparedStatementParameters &parameters)
239{
240 Q_UNUSED(selectFieldList);
242#ifdef KDB_USE_MYSQL_STMT
243 if (!m_statement || m_realParamCount <= 0)
244 return false;
245 if (mysql_stmt_errno(m_statement) == CR_SERVER_LOST) {
246 //sanity: connection lost: reconnect
247//! @todo KDbConnection should be reconnected as well!
248 done();
249 if (!init()) {
250 done();
251 return false;
252 }
253 }
254
255 if (m_resetRequired) {
256 mysql_stmt_reset(m_statement);
257 res = sqlite3_reset(prepared_st_handle);
258 if (SQLITE_OK != res) {
259 //! @todo msg?
260 return false;
261 }
262 m_resetRequired = false;
263 }
264
265 int par = 0;
266 bool dummyNull = true;
267 unsigned long str_length;
268
269 //for INSERT, we're iterating over inserting values
270 //for SELECT, we're iterating over WHERE conditions
271 KDbField::List *fieldList = 0;
272 if (m_type == SelectStatement)
273 fieldList = m_whereFields;
274 else if (m_type == InsertStatement)
275 fieldList = m_fields->fields();
276 else
277 Q_ASSERT(0); //impl. error
278
279 KDbField::ListIterator itFields(fieldList->constBegin());
280 for (QList<QVariant>::ConstIterator it(parameters.constBegin());
281 itFields != fieldList->constEnd() && arg < m_realParamCount; ++it, ++itFields, par++) {
282 if (!bindValue(*itFields, it == parameters.constEnd() ? QVariant() : *it, par))
283 return false;
284 }//for
285
286 //real execution
287 res = sqlite3_step(prepared_st_handle);
288 m_resetRequired = true;
289 if (m_type == InsertStatement && res == SQLITE_DONE) {
290 return true;
291 }
292 if (m_type == SelectStatement) {
293 //fetch result
294
295//! @todo
296 }
297#else
298 m_resetRequired = true;
300 const int missingValues = insertFieldList->fieldCount() - parameters.count();
301 KDbPreparedStatementParameters myParameters(parameters);
302 if (missingValues > 0) {
303 //! @todo can be more efficient
304 for (int i = 0; i < missingValues; i++) {
305 myParameters.append(QVariant());
306 }
307 }
308 result = connection->insertRecord(insertFieldList, myParameters);
309 }
310//! @todo support select
311#endif // !KDB_USE_MYSQL_STMT
312 return result;
313}
Specialized string for escaping.
int fieldCount() const
Meta-data for a field.
Definition KDbField.h:72
QList< KDbField * >::ConstIterator ListIterator
iterator for list of fields
Definition KDbField.h:79
bool isTextType() const
Definition KDbField.h:353
@ Integer
Definition KDbField.h:90
@ Boolean
Definition KDbField.h:92
@ ShortInteger
Definition KDbField.h:89
@ BigInteger
Definition KDbField.h:91
Type type() const
Definition KDbField.cpp:379
Prepared statement interface for backend-dependent implementations.
Type
Defines type of the prepared statement.
@ InsertStatement
INSERT statement will be prepared end executed.
QCA_EXPORT void init()
QString toString(QStringView format, QCalendar cal) const const
QString toString(QStringView format, QCalendar cal) const const
const_iterator constBegin() const const
const_iterator constEnd() const const
qsizetype count() const const
QString number(double n, char format, int precision)
QByteArray toLatin1() const const
QByteArray toUtf8() const const
QString toString(QStringView format) const const
bool isNull() const const
bool toBool() const const
QByteArray toByteArray() const const
QDate toDate() const const
QDateTime toDateTime() const const
double toDouble(bool *ok) const const
int toInt(bool *ok) const const
qlonglong toLongLong(bool *ok) const const
QString toString() const const
QTime toTime() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 12 2024 12:05:27 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.