1
/* This file is part of the KDE project
2
Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
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.
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.
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.
20
#include "mysqlpreparedstatement.h"
24
using namespace KexiDB;
26
// For example prepared MySQL statement code see:
27
// http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-execute.html
29
MySqlPreparedStatement::MySqlPreparedStatement(StatementType type, ConnectionInternal& conn,
31
: KexiDB::PreparedStatement(type, conn, fields)
32
, MySqlConnectionInternal(conn.connection)
33
#ifdef KEXI_USE_MYSQL_STMT
37
, m_resetRequired(false)
39
// KexiDBDrvDbg << "MySqlPreparedStatement: Construction" << endl;
42
mysql = dynamic_cast<KexiDB::MySqlConnectionInternal&>(conn).mysql; //copy
43
m_tempStatementString = generateStatementString();
49
bool MySqlPreparedStatement::init()
51
if (m_tempStatementString.isEmpty())
53
#ifdef KEXI_USE_MYSQL_STMT
54
m_statement = mysql_stmt_init(mysql);
56
//! @todo err 'out of memory'
59
res = mysql_stmt_prepare(m_statement,
60
(const char*)m_tempStatementString, m_tempStatementString.length());
62
//! @todo use mysql_stmt_error(stmt); to show error
66
m_realParamCount = mysql_stmt_param_count(m_statement);
67
if (m_realParamCount<=0) {
71
m_mysqlBind = new MYSQL_BIND[ m_realParamCount ];
72
memset(m_mysqlBind, 0, sizeof(MYSQL_BIND)*m_realParamCount); //safe?
78
MySqlPreparedStatement::~MySqlPreparedStatement()
83
void MySqlPreparedStatement::done()
85
#ifdef KEXI_USE_MYSQL_STMT
87
//! @todo handle errors of mysql_stmt_close()?
88
mysql_stmt_close(m_statement);
96
#ifdef KEXI_USE_MYSQL_STMT
98
m_mysqlBind[arg].buffer_type = MYSQL_TYPE_NULL; \
99
m_mysqlBind[arg].buffer = 0; \
100
m_mysqlBind[arg].buffer_length = 0; \
101
m_mysqlBind[arg].is_null = &dummyNull; \
102
m_mysqlBind[arg].length = &str_length; }
105
bool MySqlPreparedStatement::execute()
107
#ifdef KEXI_USE_MYSQL_STMT
108
if (!m_statement || m_realParamCount<=0)
110
if ( mysql_stmt_errno(m_statement) == CR_SERVER_LOST ) {
111
//sanity: connection lost: reconnect
112
//! @todo KexiDB::Connection should be reconnected as well!
120
if (m_resetRequired) {
121
mysql_stmt_reset(m_statement);
122
res = sqlite3_reset(prepared_st_handle);
123
if (SQLITE_OK != res) {
127
m_resetRequired = false;
131
bool dummyNull = true;
132
unsigned long str_length;
133
KexiDB::Field *field;
136
Field::ListIterator itFields(_dummy);
137
//for INSERT, we're iterating over inserting values
138
//for SELECT, we're iterating over WHERE conditions
139
if (m_type == SelectStatement)
140
itFields = *m_whereFields;
141
else if (m_type == InsertStatement)
142
itFields = m_fields->fieldsIterator();
144
assert(0); //impl. error
146
for (QValueListConstIterator<QVariant> it = m_args.constBegin();
147
(field = itFields.current()) && arg < m_realParamCount; ++it, ++itFields, arg++)
149
if (it==m_args.constEnd() || (*it).isNull()) {//no value to bind or the value is null: bind NULL
153
if (field->isTextType()) {
155
m_stringBuffer[ 1024 ]; ???
156
char *str = qstrncpy(m_stringBuffer, (const char*)(*it).toString().utf8(), 1024);
157
m_mysqlBind[arg].buffer_type = MYSQL_TYPE_STRING;
158
m_mysqlBind[arg].buffer = m_stringBuffer;
159
m_mysqlBind[arg].is_null = (my_bool*)0;
160
m_mysqlBind[arg].buffer_length = 1024; //?
161
m_mysqlBind[arg].length = &str_length;
163
else switch (field->type()) {
164
case KexiDB::Field::Byte:
165
case KexiDB::Field::ShortInteger:
166
case KexiDB::Field::Integer:
168
//! @todo what about unsigned > INT_MAX ?
170
const int value = (*it).toInt(&ok);
172
if (field->type()==KexiDB::Field::Byte)
173
m_mysqlBind[arg].buffer_type = MYSQL_TYPE_TINY;
174
else if (field->type()==KexiDB::Field::ShortInteger)
175
m_mysqlBind[arg].buffer_type = MYSQL_TYPE_SHORT;
176
else if (field->type()==KexiDB::Field::Integer)
177
m_mysqlBind[arg].buffer_type = MYSQL_TYPE_LONG;
179
m_mysqlBind[arg].is_null = (my_bool*)0;
180
m_mysqlBind[arg].length = 0;
182
res = sqlite3_bind_int(prepared_st_handle, arg, value);
183
if (SQLITE_OK != res) {
192
case KexiDB::Field::Float:
193
case KexiDB::Field::Double:
194
res = sqlite3_bind_double(prepared_st_handle, arg, (*it).toDouble());
195
if (SQLITE_OK != res) {
200
case KexiDB::Field::BigInteger:
202
//! @todo what about unsigned > LLONG_MAX ?
204
Q_LLONG value = (*it).toLongLong(&ok);
206
res = sqlite3_bind_int64(prepared_st_handle, arg, value);
207
if (SQLITE_OK != res) {
213
res = sqlite3_bind_null(prepared_st_handle, arg);
214
if (SQLITE_OK != res) {
221
case KexiDB::Field::Boolean:
222
res = sqlite3_bind_text(prepared_st_handle, arg,
223
QString::number((*it).toBool() ? 1 : 0).latin1(),
224
1, SQLITE_TRANSIENT /*??*/);
225
if (SQLITE_OK != res) {
230
case KexiDB::Field::Time:
231
res = sqlite3_bind_text(prepared_st_handle, arg,
232
(*it).toTime().toString(Qt::ISODate).latin1(),
233
sizeof("HH:MM:SS"), SQLITE_TRANSIENT /*??*/);
234
if (SQLITE_OK != res) {
239
case KexiDB::Field::Date:
240
res = sqlite3_bind_text(prepared_st_handle, arg,
241
(*it).toDate().toString(Qt::ISODate).latin1(),
242
sizeof("YYYY-MM-DD"), SQLITE_TRANSIENT /*??*/);
243
if (SQLITE_OK != res) {
248
case KexiDB::Field::DateTime:
249
res = sqlite3_bind_text(prepared_st_handle, arg,
250
(*it).toDateTime().toString(Qt::ISODate).latin1(),
251
sizeof("YYYY-MM-DDTHH:MM:SS"), SQLITE_TRANSIENT /*??*/);
252
if (SQLITE_OK != res) {
257
case KexiDB::Field::BLOB:
259
const QByteArray byteArray((*it).toByteArray());
260
res = sqlite3_bind_blob(prepared_st_handle, arg,
261
(const char*)byteArray, byteArray.size(), SQLITE_TRANSIENT /*??*/);
262
if (SQLITE_OK != res) {
269
KexiDBWarn << "PreparedStatement::execute(): unsupported field type: "
270
<< field->type() << " - NULL value bound to column #" << arg << endl;
271
res = sqlite3_bind_null(prepared_st_handle, arg);
272
if (SQLITE_OK != res) {
280
res = sqlite3_step(prepared_st_handle);
281
m_resetRequired = true;
282
if (m_type == InsertStatement && res == SQLITE_DONE) {
285
if (m_type == SelectStatement) {
291
m_resetRequired = true;
292
if (connection->insertRecord(*m_fields, m_args)) {
296
#endif //KEXI_USE_MYSQL_STMT