File indexing completed on 2024-04-28 15:58:54

0001 /* This file is part of the KDE project
0002    Copyright (C) 2005-2012 Jarosław Staniek <staniek@kde.org>
0003 
0004    This library is free software; you can redistribute it and/or
0005    modify it under the terms of the GNU Library General Public
0006    License as published by the Free Software Foundation; either
0007    version 2 of the License, or (at your option) any later version.
0008 
0009    This library is distributed in the hope that it will be useful,
0010    but WITHOUT ANY WARRANTY; without even the implied warranty of
0011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
0012    Library General Public License for more details.
0013 
0014    You should have received a copy of the GNU Library General Public License
0015    along with this library; see the file COPYING.LIB.  If not, write to
0016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
0017  * Boston, MA 02110-1301, USA.
0018 */
0019 
0020 #include "SqlitePreparedStatement.h"
0021 #include "KDbPreparedStatement.h"
0022 #include "sqlite_debug.h"
0023 
0024 SqlitePreparedStatement::SqlitePreparedStatement(SqliteConnectionInternal* conn)
0025         : KDbPreparedStatementInterface()
0026         , SqliteConnectionInternal(conn->connection)
0027 {
0028     data_owned = false;
0029     data = conn->data; //copy
0030 }
0031 
0032 SqlitePreparedStatement::~SqlitePreparedStatement()
0033 {
0034 }
0035 
0036 bool SqlitePreparedStatement::prepare(const KDbEscapedString& sql)
0037 {
0038     m_sqlResult = connection->prepareSql(sql);
0039     m_result = connection->result();
0040     return m_sqlResult && !m_result.isError();
0041 }
0042 
0043 bool SqlitePreparedStatement::bindValue(KDbField *field, const QVariant& value, int par)
0044 {
0045     if (value.isNull()) {
0046         //no value to bind or the value is null: bind NULL
0047         int res = sqlite3_bind_null(sqlResult()->prepared_st, par);
0048         if (res != SQLITE_OK) {
0049             m_result.setServerErrorCode(res);
0050             storeResult(&m_result);
0051             return false;
0052         }
0053         return true;
0054     }
0055     if (field->isTextType()) {
0056         //! @todo optimize: make a static copy so SQLITE_STATIC can be used
0057         const QByteArray utf8String(value.toString().toUtf8());
0058         int res = sqlite3_bind_text(sqlResult()->prepared_st, par,
0059                                     utf8String.constData(), utf8String.length(), SQLITE_TRANSIENT /*??*/);
0060         if (res != SQLITE_OK) {
0061             m_result.setServerErrorCode(res);
0062             storeResult(&m_result);
0063             return false;
0064         }
0065         return true;
0066     }
0067 
0068     switch (field->type()) {
0069     case KDbField::Byte:
0070     case KDbField::ShortInteger:
0071     case KDbField::Integer: {
0072         //! @todo what about unsigned > INT_MAX ?
0073         bool ok;
0074         const int intValue = value.toInt(&ok);
0075         if (ok) {
0076             int res = sqlite3_bind_int(sqlResult()->prepared_st, par, intValue);
0077             if (res != SQLITE_OK) {
0078                 m_result.setServerErrorCode(res);
0079                 storeResult(&m_result);
0080                 return false;
0081             }
0082         } else {
0083             int res = sqlite3_bind_null(sqlResult()->prepared_st, par);
0084             if (res != SQLITE_OK) {
0085                 m_result.setServerErrorCode(res);
0086                 storeResult(&m_result);
0087                 return false;
0088             }
0089         }
0090         break;
0091     }
0092     case KDbField::Float:
0093     case KDbField::Double: {
0094         int res = sqlite3_bind_double(sqlResult()->prepared_st, par, value.toDouble());
0095         if (res != SQLITE_OK) {
0096             m_result.setServerErrorCode(res);
0097             storeResult(&m_result);
0098             return false;
0099         }
0100         break;
0101     }
0102     case KDbField::BigInteger: {
0103         //! @todo what about unsigned > LLONG_MAX ?
0104         bool ok;
0105         const qint64 int64Value = value.toLongLong(&ok);
0106         if (ok) {
0107             int res = sqlite3_bind_int64(sqlResult()->prepared_st, par, int64Value);
0108             if (res != SQLITE_OK) {
0109                 m_result.setServerErrorCode(res);
0110                 storeResult(&m_result);
0111                 return false;
0112             }
0113         } else {
0114             int res = sqlite3_bind_null(sqlResult()->prepared_st, par);
0115             if (res != SQLITE_OK) {
0116                 m_result.setServerErrorCode(res);
0117                 storeResult(&m_result);
0118                 return false;
0119             }
0120         }
0121         break;
0122     }
0123     case KDbField::Boolean: {
0124         int res = sqlite3_bind_text(sqlResult()->prepared_st, par, value.toBool() ? "1" : "0",
0125                                     1, SQLITE_TRANSIENT /*??*/);
0126         if (res != SQLITE_OK) {
0127             m_result.setServerErrorCode(res);
0128             storeResult(&m_result);
0129             return false;
0130         }
0131         break;
0132     }
0133     case KDbField::Time: {
0134         int res = sqlite3_bind_text(sqlResult()->prepared_st, par,
0135                                     qPrintable(KDbUtils::toISODateStringWithMs(value.toTime())),
0136                                     QLatin1String("HH:MM:SS").size(), SQLITE_TRANSIENT /*??*/);
0137         if (res != SQLITE_OK) {
0138             m_result.setServerErrorCode(res);
0139             storeResult(&m_result);
0140             return false;
0141         }
0142         break;
0143     }
0144     case KDbField::Date: {
0145         int res = sqlite3_bind_text(sqlResult()->prepared_st, par,
0146                                     qPrintable(value.toDate().toString(Qt::ISODate)),
0147                                     QLatin1String("YYYY-MM-DD").size(), SQLITE_TRANSIENT /*??*/);
0148         if (res != SQLITE_OK) {
0149             m_result.setServerErrorCode(res);
0150             storeResult(&m_result);
0151             return false;
0152         }
0153         break;
0154     }
0155     case KDbField::DateTime: {
0156         int res = sqlite3_bind_text(sqlResult()->prepared_st, par,
0157                                 qPrintable(KDbUtils::toISODateStringWithMs(value.toDateTime())),
0158                                 QLatin1String("YYYY-MM-DDTHH:MM:SS").size(), SQLITE_TRANSIENT /*??*/);
0159         if (res != SQLITE_OK) {
0160             m_result.setServerErrorCode(res);
0161             storeResult(&m_result);
0162             return false;
0163         }
0164         break;
0165     }
0166     case KDbField::BLOB: {
0167         const QByteArray byteArray(value.toByteArray());
0168         int res = sqlite3_bind_blob(sqlResult()->prepared_st, par,
0169                                     byteArray.constData(), byteArray.size(), SQLITE_TRANSIENT /*??*/);
0170         if (res != SQLITE_OK) {
0171             m_result.setServerErrorCode(res);
0172             storeResult(&m_result);
0173             return false;
0174         }
0175         break;
0176     }
0177     default: {
0178         sqliteWarning() << "unsupported field type:"
0179                 << field->type() << "- NULL value bound to column #" << par;
0180         int res = sqlite3_bind_null(sqlResult()->prepared_st, par);
0181         if (res != SQLITE_OK) {
0182             m_result.setServerErrorCode(res);
0183             storeResult(&m_result);
0184             return false;
0185         }
0186     }
0187     } //switch
0188     return true;
0189 }
0190 
0191 QSharedPointer<KDbSqlResult> SqlitePreparedStatement::execute(
0192     KDbPreparedStatement::Type type,
0193     const KDbField::List& selectFieldList,
0194     KDbFieldList* insertFieldList,
0195     const KDbPreparedStatementParameters& parameters)
0196 {
0197     Q_UNUSED(insertFieldList);
0198     if (!sqlResult()->prepared_st) {
0199         return QSharedPointer<KDbSqlResult>();
0200     }
0201 
0202     int par = 1; // par.index counted from 1
0203     KDbField::ListIterator itFields(selectFieldList.constBegin());
0204     for (QList<QVariant>::ConstIterator it = parameters.constBegin();
0205          itFields != selectFieldList.constEnd();
0206          it += (it == parameters.constEnd() ? 0 : 1), ++itFields, par++)
0207     {
0208         if (!bindValue(*itFields, it == parameters.constEnd() ? QVariant() : *it, par))
0209             return QSharedPointer<KDbSqlResult>();
0210     }
0211 
0212     //real execution
0213     const int res = sqlite3_step(sqlResult()->prepared_st);
0214     if (type == KDbPreparedStatement::InsertStatement) {
0215         const bool ok = res == SQLITE_DONE;
0216         if (ok) {
0217             m_result = KDbResult();
0218         } else {
0219             m_result.setServerErrorCode(res);
0220             storeResult(&m_result);
0221             sqliteWarning() << m_result << QString::fromLatin1(sqlite3_sql(sqlResult()->prepared_st));
0222         }
0223         (void)sqlite3_reset(sqlResult()->prepared_st);
0224         return m_sqlResult;
0225     }
0226     else if (type == KDbPreparedStatement::SelectStatement) {
0227         //! @todo fetch result
0228         const bool ok = res == SQLITE_ROW;
0229         storeResult(&m_result);
0230         if (ok) {
0231             m_result = KDbResult();
0232         } else {
0233             m_result.setServerErrorCode(res);
0234             storeResult(&m_result);
0235             sqliteWarning() << m_result << QString::fromLatin1(sqlite3_sql(sqlResult()->prepared_st));
0236         }
0237         (void)sqlite3_reset(sqlResult()->prepared_st);
0238         return m_sqlResult;
0239     }
0240     return QSharedPointer<KDbSqlResult>();
0241 }