~ubuntu-branches/ubuntu/precise/koffice/precise

« back to all changes in this revision

Viewing changes to kexi/kexidb/drivers/mySQL/mysqlpreparedstatement.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2006-04-20 21:38:53 UTC
  • mfrom: (1.1.3 upstream)
  • Revision ID: james.westby@ubuntu.com-20060420213853-j5lxluqvymxt2zny
Tags: 1:1.5.0-0ubuntu2
UbuntuĀ uploadĀ 

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* This file is part of the KDE project
 
2
   Copyright (C) 2006 Jaroslaw Staniek <js@iidea.pl>
 
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 <kdebug.h>
 
22
#include <errmsg.h>
 
23
 
 
24
using namespace KexiDB;
 
25
 
 
26
// For example prepared MySQL statement code see:
 
27
// http://dev.mysql.com/doc/refman/4.1/en/mysql-stmt-execute.html
 
28
 
 
29
MySqlPreparedStatement::MySqlPreparedStatement(StatementType type, ConnectionInternal& conn, 
 
30
        FieldList& fields)
 
31
 : KexiDB::PreparedStatement(type, conn, fields)
 
32
 , MySqlConnectionInternal(conn.connection)
 
33
#ifdef KEXI_USE_MYSQL_STMT
 
34
 , m_statement(0)
 
35
 , m_mysqlBind(0)
 
36
#endif
 
37
 , m_resetRequired(false)
 
38
{
 
39
//      KexiDBDrvDbg << "MySqlPreparedStatement: Construction" << endl;
 
40
 
 
41
        mysql_owned = false;
 
42
        mysql = dynamic_cast<KexiDB::MySqlConnectionInternal&>(conn).mysql; //copy
 
43
        m_tempStatementString = generateStatementString();
 
44
 
 
45
        if (!init())
 
46
                done();
 
47
}
 
48
 
 
49
bool MySqlPreparedStatement::init()
 
50
{
 
51
        if (m_tempStatementString.isEmpty())
 
52
                return false;
 
53
#ifdef KEXI_USE_MYSQL_STMT
 
54
        m_statement = mysql_stmt_init(mysql);
 
55
        if (!m_statement) {
 
56
//! @todo err 'out of memory'
 
57
                return false;
 
58
        }
 
59
        res = mysql_stmt_prepare(m_statement, 
 
60
                (const char*)m_tempStatementString, m_tempStatementString.length());
 
61
        if (0 != res) {
 
62
//! @todo use mysql_stmt_error(stmt); to show error
 
63
                return false;
 
64
        }
 
65
 
 
66
        m_realParamCount = mysql_stmt_param_count(m_statement);
 
67
        if (m_realParamCount<=0) {
 
68
//! @todo err 
 
69
                return false;
 
70
        }
 
71
        m_mysqlBind = new MYSQL_BIND[ m_realParamCount ];
 
72
        memset(m_mysqlBind, 0, sizeof(MYSQL_BIND)*m_realParamCount); //safe?
 
73
#endif
 
74
        return true;
 
75
}
 
76
 
 
77
 
 
78
MySqlPreparedStatement::~MySqlPreparedStatement()
 
79
{
 
80
        done();
 
81
}
 
82
 
 
83
void MySqlPreparedStatement::done()
 
84
{
 
85
#ifdef KEXI_USE_MYSQL_STMT
 
86
        if (m_statement) {
 
87
//! @todo handle errors of mysql_stmt_close()?
 
88
                mysql_stmt_close(m_statement);
 
89
                m_statement = 0;
 
90
        }
 
91
        delete m_mysqlBind;
 
92
        m_mysqlBind = 0;
 
93
#endif
 
94
}
 
95
 
 
96
#ifdef KEXI_USE_MYSQL_STMT
 
97
#define BIND_NULL { \
 
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; }
 
103
#endif
 
104
 
 
105
bool MySqlPreparedStatement::execute()
 
106
{
 
107
#ifdef KEXI_USE_MYSQL_STMT
 
108
        if (!m_statement || m_realParamCount<=0)
 
109
                return false;
 
110
        if ( mysql_stmt_errno(m_statement) == CR_SERVER_LOST ) {
 
111
                //sanity: connection lost: reconnect
 
112
//! @todo KexiDB::Connection should be reconnected as well!
 
113
                done();
 
114
                if (!init()) {
 
115
                        done();
 
116
                        return false;
 
117
                }
 
118
        }
 
119
 
 
120
        if (m_resetRequired) {
 
121
                mysql_stmt_reset(m_statement);
 
122
                res = sqlite3_reset(prepared_st_handle);
 
123
                if (SQLITE_OK != res) {
 
124
                        //! @todo msg?
 
125
                        return false;
 
126
                }
 
127
                m_resetRequired = false;
 
128
        }
 
129
 
 
130
        int arg = 0;
 
131
        bool dummyNull = true;
 
132
        unsigned long str_length;
 
133
        KexiDB::Field *field;
 
134
 
 
135
        Field::List _dummy;
 
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();
 
143
        else
 
144
                assert(0); //impl. error
 
145
 
 
146
        for (QValueListConstIterator<QVariant> it = m_args.constBegin(); 
 
147
                (field = itFields.current()) && arg < m_realParamCount; ++it, ++itFields, arg++)
 
148
        {
 
149
                if (it==m_args.constEnd() || (*it).isNull()) {//no value to bind or the value is null: bind NULL
 
150
                        BIND_NULL;
 
151
                        continue;
 
152
                }
 
153
                if (field->isTextType()) {
 
154
//! @todo optimize
 
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;
 
162
                }
 
163
                else switch (field->type()) {
 
164
                case KexiDB::Field::Byte:
 
165
                case KexiDB::Field::ShortInteger:
 
166
                case KexiDB::Field::Integer:
 
167
                {
 
168
//! @todo what about unsigned > INT_MAX ?
 
169
                        bool ok;
 
170
                        const int value = (*it).toInt(&ok);
 
171
                        if (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;
 
178
 
 
179
                                m_mysqlBind[arg].is_null = (my_bool*)0;
 
180
                                m_mysqlBind[arg].length = 0;
 
181
 
 
182
                                res = sqlite3_bind_int(prepared_st_handle, arg, value);
 
183
                                if (SQLITE_OK != res) {
 
184
                                        //! @todo msg?
 
185
                                        return false;
 
186
                                }
 
187
                        }
 
188
                        else
 
189
                                BIND_NULL;
 
190
                        break;
 
191
                }
 
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) {
 
196
                                //! @todo msg?
 
197
                                return false;
 
198
                        }
 
199
                        break;
 
200
                case KexiDB::Field::BigInteger:
 
201
                {
 
202
//! @todo what about unsigned > LLONG_MAX ?
 
203
                        bool ok;
 
204
                        Q_LLONG value = (*it).toLongLong(&ok);
 
205
                        if (ok) {
 
206
                                res = sqlite3_bind_int64(prepared_st_handle, arg, value);
 
207
                                if (SQLITE_OK != res) {
 
208
                                        //! @todo msg?
 
209
                                        return false;
 
210
                                }
 
211
                        }
 
212
                        else {
 
213
                                res = sqlite3_bind_null(prepared_st_handle, arg);
 
214
                                if (SQLITE_OK != res) {
 
215
                                        //! @todo msg?
 
216
                                        return false;
 
217
                                }
 
218
                        }
 
219
                        break;
 
220
                }
 
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) {
 
226
                                //! @todo msg?
 
227
                                return false;
 
228
                        }
 
229
                        break;
 
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) {
 
235
                                //! @todo msg?
 
236
                                return false;
 
237
                        }
 
238
                        break;
 
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) {
 
244
                                //! @todo msg?
 
245
                                return false;
 
246
                        }
 
247
                        break;
 
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) {
 
253
                                //! @todo msg?
 
254
                                return false;
 
255
                        }
 
256
                        break;
 
257
                case KexiDB::Field::BLOB:
 
258
                {
 
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) {
 
263
                                //! @todo msg?
 
264
                                return false;
 
265
                        }
 
266
                        break;
 
267
                }
 
268
                default:
 
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) {
 
273
                                //! @todo msg?
 
274
                                return false;
 
275
                        }
 
276
                } //switch
 
277
        }
 
278
 
 
279
        //real execution
 
280
        res = sqlite3_step(prepared_st_handle);
 
281
        m_resetRequired = true;
 
282
        if (m_type == InsertStatement && res == SQLITE_DONE) {
 
283
                return true;
 
284
        }
 
285
        if (m_type == SelectStatement) {
 
286
                //fetch result
 
287
 
 
288
                //todo
 
289
        }
 
290
#else 
 
291
        m_resetRequired = true;
 
292
        if (connection->insertRecord(*m_fields, m_args)) {
 
293
                return true;
 
294
        }
 
295
        
 
296
#endif //KEXI_USE_MYSQL_STMT
 
297
        return false;
 
298
}