File indexing completed on 2024-03-24 16:11:19

0001 /* This file is part of the KDE project
0002    Copyright (C) 2005-2016 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 "KDbPreparedStatement.h"
0021 #include "KDbPreparedStatementInterface.h"
0022 #include "KDbSqlResult.h"
0023 #include "KDbTableSchema.h"
0024 #include "kdb_debug.h"
0025 
0026 KDbPreparedStatement::Data::Data()
0027     : Data(InvalidStatement, nullptr, nullptr, QStringList())
0028 {
0029 }
0030 
0031 KDbPreparedStatement::Data::Data(Type _type, KDbPreparedStatementInterface* _iface,
0032                                  KDbFieldList* _fields,
0033      const QStringList& _whereFieldNames)
0034     : type(_type), fields(_fields), whereFieldNames(_whereFieldNames)
0035     , fieldsForParameters(nullptr), whereFields(nullptr), dirty(true), iface(_iface)
0036     , lastInsertRecordId(std::numeric_limits<quint64>::max())
0037 {
0038 }
0039 
0040 KDbPreparedStatement::Data::~Data()
0041 {
0042     delete iface;
0043     delete whereFields;
0044 }
0045 
0046 KDbPreparedStatement::KDbPreparedStatement()
0047     : d( new Data() )
0048 {
0049 }
0050 
0051 KDbPreparedStatement::KDbPreparedStatement(KDbPreparedStatementInterface* iface,
0052                                            Type type, KDbFieldList* fields,
0053                                            const QStringList& whereFieldNames)
0054     : d( new Data(type, iface, fields, whereFieldNames) )
0055 {
0056 }
0057 
0058 KDbPreparedStatement::~KDbPreparedStatement()
0059 {
0060 }
0061 
0062 bool KDbPreparedStatement::execute(const KDbPreparedStatementParameters& parameters)
0063 {
0064     if (d->dirty) {
0065         KDbEscapedString s;
0066         if (!generateStatementString(&s)) { // sets d->fieldsForParameters too
0067             m_result.setCode(ERR_OTHER);
0068             return false;
0069         }
0070 //! @todo error message?
0071         if (s.isEmpty()) {
0072             m_result.setCode(ERR_OTHER);
0073             return false;
0074         }
0075         if (!d->iface->prepare(s)) {
0076             m_result.setCode(ERR_OTHER);
0077             return false;
0078         }
0079         d->dirty = false;
0080     }
0081     QSharedPointer<KDbSqlResult> result
0082         = d->iface->execute(d->type, *d->fieldsForParameters, d->fields, parameters);
0083     if (!result) {
0084         return false;
0085     }
0086     d->lastInsertRecordId = result->lastInsertRecordId();
0087     return true;
0088 }
0089 
0090 bool KDbPreparedStatement::generateStatementString(KDbEscapedString * s)
0091 {
0092     s->reserve(1024);
0093     switch (d->type) {
0094     case SelectStatement:
0095         return generateSelectStatementString(s);
0096     case InsertStatement:
0097         return generateInsertStatementString(s);
0098     default:;
0099     }
0100     kdbCritical() << "Unsupported type" << d->type;
0101     return false;
0102 }
0103 
0104 bool KDbPreparedStatement::generateSelectStatementString(KDbEscapedString * s)
0105 {
0106 //! @todo only tables and trivial queries supported for select...
0107     *s = "SELECT ";
0108     bool first = true;
0109     foreach(KDbField *f, *d->fields->fields()) {
0110         if (first)
0111             first = false;
0112         else
0113             s->append(", ");
0114         s->append(f->name());
0115     }
0116     // create WHERE
0117     first = true;
0118     delete d->whereFields;
0119     d->whereFields = new KDbField::List();
0120     foreach(const QString& whereItem, d->whereFieldNames) {
0121         if (first) {
0122             s->append(" WHERE ");
0123             first = false;
0124         }
0125         else
0126             s->append(" AND ");
0127         KDbField *f = d->fields->field(whereItem);
0128         if (!f) {
0129             kdbWarning() << "field" << whereItem << "not found, aborting";
0130             s->clear();
0131             return false;
0132         }
0133         d->whereFields->append(f);
0134         s->append(whereItem.toUtf8() + "=?");
0135     }
0136     d->fieldsForParameters = d->whereFields;
0137     return true;
0138 }
0139 
0140 bool KDbPreparedStatement::generateInsertStatementString(KDbEscapedString * s)
0141 {
0142     //! @todo only tables supported for insert; what about views?
0143     KDbTableSchema *table = d->fields->isEmpty() ? nullptr : d->fields->field(0)->table();
0144     if (!table)
0145         return false; //err
0146 
0147     KDbEscapedString namesList;
0148     bool first = true;
0149     //we are using a selection of fields only
0150     const bool allTableFieldsUsed = dynamic_cast<KDbTableSchema*>(d->fields);
0151     foreach(const KDbField* f, *d->fields->fields()) {
0152         if (first) {
0153             s->append("?");
0154             if (!allTableFieldsUsed)
0155                 namesList = KDbEscapedString(f->name());
0156             first = false;
0157         } else {
0158             s->append(",?");
0159             if (!allTableFieldsUsed) {
0160                 namesList.append(", ");
0161                 namesList.append(f->name());
0162             }
0163         }
0164     }
0165     s->append(")");
0166     s->prepend(KDbEscapedString("INSERT INTO ") + table->name()
0167                + (allTableFieldsUsed ? KDbEscapedString() : (KDbEscapedString(" (") + namesList + ')'))
0168                + " VALUES (");
0169     d->fieldsForParameters = d->fields->fields();
0170     return true;
0171 }
0172 
0173 bool KDbPreparedStatement::isValid() const
0174 {
0175     return d->type != InvalidStatement;
0176 }
0177 
0178 KDbPreparedStatement::Type KDbPreparedStatement::type() const
0179 {
0180     return d->type;
0181 }
0182 
0183 void KDbPreparedStatement::setType(KDbPreparedStatement::Type type)
0184 {
0185     d->type = type;
0186     d->dirty = true;
0187 }
0188 
0189 const KDbFieldList* KDbPreparedStatement::fields() const
0190 {
0191     return d->fields;
0192 }
0193 
0194 void KDbPreparedStatement::setFields(KDbFieldList* fields)
0195 {
0196     if (fields) {
0197         d->fields = fields;
0198         d->dirty = true;
0199     }
0200 }
0201 
0202 QStringList KDbPreparedStatement::whereFieldNames() const
0203 {
0204     return d->whereFieldNames;
0205 }
0206 
0207 void KDbPreparedStatement::setWhereFieldNames(const QStringList& whereFieldNames)
0208 {
0209     d->whereFieldNames = whereFieldNames;
0210     d->dirty = true;
0211 }
0212 
0213 quint64 KDbPreparedStatement::lastInsertRecordId() const
0214 {
0215     return d->lastInsertRecordId;
0216 }
0217 
0218 /*bool KDbPreparedStatement::insert()
0219 {
0220   const bool res = m_conn->drv_prepareStatement(this);
0221   const bool res = m_conn->drv_insertRecord(this);
0222   clearArguments();
0223   return res;
0224 }
0225 
0226 bool KDbPreparedStatement::select()
0227 {
0228   const bool res = m_conn->drv_bindArgumentForPreparedStatement(this, m_args.count()-1);
0229 }*/