|
|
|
/* This file is part of the KDE project
|
|
|
|
Copyright (C) 2005 Jaroslaw Staniek <js@iidea.pl>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License as published by the Free Software Foundation; either
|
|
|
|
version 2 of the License, or (at your option) any later version.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "sqlitepreparedstatement.h"
|
|
|
|
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
using namespace KexiDB;
|
|
|
|
|
|
|
|
SQLitePreparedStatement::SQLitePreparedStatement(StatementType type, ConnectionInternal& conn,
|
|
|
|
FieldList& fields)
|
|
|
|
: KexiDB::PreparedStatement(type, conn, fields)
|
|
|
|
, SQLiteConnectionInternal(conn.connection)
|
|
|
|
, prepared_st_handle(0)
|
|
|
|
, m_resetRequired(false)
|
|
|
|
{
|
|
|
|
data_owned = false;
|
|
|
|
data = dynamic_cast<KexiDB::SQLiteConnectionInternal&>(conn).data; //copy
|
|
|
|
|
|
|
|
temp_st = generateStatementString();
|
|
|
|
#ifdef SQLITE2
|
|
|
|
//! @todo
|
|
|
|
#else
|
|
|
|
if (!temp_st.isEmpty()) {
|
|
|
|
res = sqlite3_prepare(
|
|
|
|
data, /* Database handle */
|
|
|
|
temp_st, //const char *zSql, /* SQL statement, UTF-8 encoded */
|
|
|
|
temp_st.length(), //int nBytes, /* Length of zSql in bytes. */
|
|
|
|
&prepared_st_handle, //sqlite3_stmt **ppStmt, /* OUT: Statement handle */
|
|
|
|
0 //const char **pzTail /* OUT: Pointer to unused portion of zSql */
|
|
|
|
);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo copy error msg
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
SQLitePreparedStatement::~SQLitePreparedStatement()
|
|
|
|
{
|
|
|
|
#ifdef SQLITE2
|
|
|
|
//! @todo
|
|
|
|
#else
|
|
|
|
sqlite3_finalize(prepared_st_handle);
|
|
|
|
prepared_st_handle = 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
bool SQLitePreparedStatement::execute()
|
|
|
|
{
|
|
|
|
#ifdef SQLITE2
|
|
|
|
//! @todo
|
|
|
|
#else
|
|
|
|
if (!prepared_st_handle)
|
|
|
|
return false;
|
|
|
|
if (m_resetRequired) {
|
|
|
|
res = sqlite3_reset(prepared_st_handle);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
m_resetRequired = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
int arg=1; //arg index counted from 1
|
|
|
|
KexiDB::Field *field;
|
|
|
|
|
|
|
|
Field::List _dummy;
|
|
|
|
Field::ListIterator itFields(_dummy);
|
|
|
|
//for INSERT, we're iterating over inserting values
|
|
|
|
//for SELECT, we're iterating over WHERE conditions
|
|
|
|
if (m_type == SelectStatement)
|
|
|
|
itFields = *m_whereFields;
|
|
|
|
else if (m_type == InsertStatement)
|
|
|
|
itFields = m_fields->fieldsIterator();
|
|
|
|
else
|
|
|
|
assert(0); //impl. error
|
|
|
|
|
|
|
|
for (TQValueListConstIterator<TQVariant> it = m_args.constBegin();
|
|
|
|
(field = itFields.current()); ++it, ++itFields, arg++)
|
|
|
|
{
|
|
|
|
if (it==m_args.constEnd() || (*it).isNull()) {//no value to bind or the value is null: bind NULL
|
|
|
|
res = sqlite3_bind_null(prepared_st_handle, arg);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (field->isTextType()) {
|
|
|
|
//! @todo optimize: make a static copy so SQLITE_STATIC can be used
|
|
|
|
TQCString utf8String((*it).toString().utf8());
|
|
|
|
res = sqlite3_bind_text(prepared_st_handle, arg,
|
|
|
|
(const char*)utf8String, utf8String.length(), SQLITE_TRANSIENT /*??*/);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else switch (field->type()) {
|
|
|
|
case KexiDB::Field::Byte:
|
|
|
|
case KexiDB::Field::ShortInteger:
|
|
|
|
case KexiDB::Field::Integer:
|
|
|
|
{
|
|
|
|
//! @todo what about unsigned > INT_MAX ?
|
|
|
|
bool ok;
|
|
|
|
const int value = (*it).toInt(&ok);
|
|
|
|
if (ok) {
|
|
|
|
res = sqlite3_bind_int(prepared_st_handle, arg, value);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
res = sqlite3_bind_null(prepared_st_handle, arg);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case KexiDB::Field::Float:
|
|
|
|
case KexiDB::Field::Double:
|
|
|
|
res = sqlite3_bind_double(prepared_st_handle, arg, (*it).toDouble());
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KexiDB::Field::BigInteger:
|
|
|
|
{
|
|
|
|
//! @todo what about unsigned > LLONG_MAX ?
|
|
|
|
bool ok;
|
|
|
|
TQ_LLONG value = (*it).toLongLong(&ok);
|
|
|
|
if (ok) {
|
|
|
|
res = sqlite3_bind_int64(prepared_st_handle, arg, value);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
res = sqlite3_bind_null(prepared_st_handle, arg);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case KexiDB::Field::Boolean:
|
|
|
|
res = sqlite3_bind_text(prepared_st_handle, arg,
|
|
|
|
TQString::number((*it).toBool() ? 1 : 0).latin1(),
|
|
|
|
1, SQLITE_TRANSIENT /*??*/);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KexiDB::Field::Time:
|
|
|
|
res = sqlite3_bind_text(prepared_st_handle, arg,
|
|
|
|
TQString((*it).toTime().toString(Qt::ISODate)).latin1(),
|
|
|
|
sizeof("HH:MM:SS"), SQLITE_TRANSIENT /*??*/);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KexiDB::Field::Date:
|
|
|
|
res = sqlite3_bind_text(prepared_st_handle, arg,
|
|
|
|
TQString((*it).toDate().toString(Qt::ISODate)).latin1(),
|
|
|
|
sizeof("YYYY-MM-DD"), SQLITE_TRANSIENT /*??*/);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KexiDB::Field::DateTime:
|
|
|
|
res = sqlite3_bind_text(prepared_st_handle, arg,
|
|
|
|
(*it).toDateTime().toString(Qt::ISODate).latin1(),
|
|
|
|
sizeof("YYYY-MM-DDTHH:MM:SS"), SQLITE_TRANSIENT /*??*/);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case KexiDB::Field::BLOB:
|
|
|
|
{
|
|
|
|
const TQByteArray byteArray((*it).toByteArray());
|
|
|
|
res = sqlite3_bind_blob(prepared_st_handle, arg,
|
|
|
|
(const char*)byteArray, byteArray.size(), SQLITE_TRANSIENT /*??*/);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
KexiDBWarn << "PreparedStatement::execute(): unsupported field type: "
|
|
|
|
<< field->type() << " - NULL value bound to column #" << arg << endl;
|
|
|
|
res = sqlite3_bind_null(prepared_st_handle, arg);
|
|
|
|
if (SQLITE_OK != res) {
|
|
|
|
//! @todo msg?
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} //switch
|
|
|
|
}
|
|
|
|
|
|
|
|
//real execution
|
|
|
|
res = sqlite3_step(prepared_st_handle);
|
|
|
|
m_resetRequired = true;
|
|
|
|
if (m_type == InsertStatement && res == SQLITE_DONE) {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if (m_type == SelectStatement) {
|
|
|
|
//fetch result
|
|
|
|
|
|
|
|
//todo
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|