KDb

MysqlPreparedStatement.cpp
1 /* This file is part of the KDE project
2  Copyright (C) 2006-2012 JarosÅ‚aw Staniek <[email protected]>
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 
27 MysqlPreparedStatement::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 
44 bool 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 
70 MysqlPreparedStatement::~MysqlPreparedStatement()
71 {
72  done();
73 }
74 
75 void 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 
88 bool 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 
102 bool 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;
157  case KDbField::BigInteger: {
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  }
176  case KDbField::Boolean:
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,
187  value.toTime().toString(Qt::ISODate).toLatin1(),
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,
196  value.toDate().toString(Qt::ISODate).toLatin1(),
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 
235 QSharedPointer<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 }
@ InsertStatement
INSERT statement will be prepared end executed.
bool isNull() const const
QString number(int n, int base)
QCA_EXPORT void init()
int count(const T &value) const const
Specialized string for escaping.
QByteArray toLatin1() const const
QList::const_iterator constBegin() const const
QByteArray toByteArray() const const
qlonglong toLongLong(bool *ok) const const
QDate toDate() const const
double toDouble(bool *ok) const const
bool isTextType() const
Definition: KDbField.h:353
@ Integer
Definition: KDbField.h:90
QByteArray toUtf8() const const
int toInt(bool *ok) const const
QList< KDbField * >::ConstIterator ListIterator
iterator for list of fields
Definition: KDbField.h:79
@ BigInteger
Definition: KDbField.h:91
Type type() const
Definition: KDbField.cpp:379
@ Double
Definition: KDbField.h:97
bool toBool() const const
@ Byte
Definition: KDbField.h:87
Type
Defines type of the prepared statement.
Prepared statement interface for backend-dependent implementations.
QDateTime toDateTime() const const
@ Boolean
Definition: KDbField.h:92
QList::const_iterator constEnd() const const
QTime toTime() const const
Meta-data for a field.
Definition: KDbField.h:71
QString toString(Qt::DateFormat format) const const
QString toString(Qt::DateFormat format) const const
int fieldCount() const
@ Float
Definition: KDbField.h:96
QString toString(Qt::DateFormat format) const const
@ ShortInteger
Definition: KDbField.h:89
QString toString() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jun 25 2022 06:21:34 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.