File indexing completed on 2024-04-14 14:53:32

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 #ifndef KDB_PREPAREDSTATEMENT_H
0021 #define KDB_PREPAREDSTATEMENT_H
0022 
0023 #include <QVariant>
0024 #include <QStringList>
0025 #include <QSharedData>
0026 
0027 #include "KDbField.h"
0028 #include "KDbResult.h"
0029 
0030 class KDbFieldList;
0031 class KDbPreparedStatementInterface;
0032 
0033 //! Prepared statement paraneters used in KDbPreparedStatement::execute()
0034 typedef QList<QVariant> KDbPreparedStatementParameters;
0035 
0036 /*! @short Prepared database command for optimizing sequences of multiple database actions
0037 
0038   Currently INSERT and SELECT statements are supported.
0039   For example when using KDbPreparedStatement for INSERTs,
0040   you can gain about 30% speedup compared to using multiple
0041   connection.insertRecord(*tabelSchema, dbRecordBuffer).
0042 
0043   To use KDbPreparedStatement, create is using KDbConnection:prepareStatement(),
0044   providing table schema; set up parameters using operator << ( const QVariant& value );
0045   and call execute() when ready. KDbPreparedStatement objects are accessed
0046   using KDE shared pointers, i.e KDbPreparedStatement, so you do not need
0047   to remember about destroying them. However, when underlying KDbConnection object
0048   is destroyed, KDbPreparedStatement should not be used.
0049 
0050   Let's assume tableSchema contains two columns NUMBER integer and TEXT text.
0051   Following code inserts 10000 records with random numbers and text strings
0052   obtained elsewhere using getText(i).
0053   @code
0054   bool insertMultiple(KDbConnection* conn, KDbTableSchema* tableSchema)
0055   {
0056     KDbPreparedStatement statement = conn->prepareStatement(
0057       KDbPreparedStatement::Insert, tableSchema);
0058     for (i=0; i<10000; i++) {
0059       KDbPreparedStatementParameters parameters;
0060       parameters << qrand() << getText(i);
0061       if (!statement.execute(parameters))
0062         return false;
0063     }
0064     return true;
0065   }
0066   @endcode
0067 
0068   If you do not call clearParameters() after every insert, you can insert
0069   the same value multiple times using execute() what increases efficiency even more.
0070 
0071   Another use case is inserting large objects (BLOBs or CLOBs).
0072   Depending on database backend, you can avoid escaping BLOBs.
0073   See KexiFormView::storeData() for example use.
0074 */
0075 class KDB_EXPORT KDbPreparedStatement : public KDbResultable
0076 {
0077 public:
0078 
0079     //! Defines type of the prepared statement.
0080     enum Type {
0081         InvalidStatement, //!< Used only in invalid statements
0082         SelectStatement,  //!< SELECT statement will be prepared end executed
0083         InsertStatement   //!< INSERT statement will be prepared end executed
0084     };
0085 
0086     //! @internal
0087     class KDB_EXPORT Data : public QSharedData {
0088     public:
0089         Data();
0090         Data(Type _type, KDbPreparedStatementInterface* _iface, KDbFieldList* _fields,
0091              const QStringList& _whereFieldNames);
0092         ~Data();
0093         Type type;
0094         KDbFieldList *fields;
0095         QStringList whereFieldNames;
0096         const KDbField::List* fieldsForParameters; //!< fields where we'll put the inserted parameters
0097         KDbField::List* whereFields; //!< temporary, used for select statements, based on whereFieldNames
0098         bool dirty; //!< true if the statement has to be internally
0099                     //!< prepared (possible again) before calling executeInternal()
0100         KDbPreparedStatementInterface *iface;
0101         quint64 lastInsertRecordId;
0102     };
0103 
0104     //! Creates an invalid prepared statement.
0105     KDbPreparedStatement();
0106 
0107     ~KDbPreparedStatement() override;
0108 
0109     bool isValid() const;
0110 
0111     KDbPreparedStatement::Type type() const;
0112 
0113     void setType(KDbPreparedStatement::Type type);
0114 
0115     const KDbFieldList* fields() const;
0116 
0117     //! Sets fields for the statement. Does nothing if @a fields is @c nullptr.
0118     void setFields(KDbFieldList* fields);
0119 
0120     QStringList whereFieldNames() const;
0121 
0122     void setWhereFieldNames(const QStringList& whereFieldNames);
0123 
0124     /*! Executes the prepared statement using @a parameters parameters.
0125      A number parameters set up for the statement must be the same as a number of fields
0126      defined in the underlying database table.
0127      @return false on failure. Detailed error status can be obtained
0128      from KDbConnection object that was used to create this statement object. */
0129     bool execute(const KDbPreparedStatementParameters& parameters);
0130 
0131     /*! @return unique identifier of the most recently inserted record.
0132      Typically this is just primary key value. This identifier could be reused when we want
0133      to reference just inserted record. If there was no insertion recently performed,
0134      std::numeric_limits<quint64>::max() is returned. */
0135     quint64 lastInsertRecordId() const;
0136 
0137 protected:
0138     //! Creates a new prepared statement. In your code use
0139     //! Users call KDbConnection:prepareStatement() instead.
0140     KDbPreparedStatement(KDbPreparedStatementInterface* iface, Type type,
0141                          KDbFieldList* fields,
0142                          const QStringList& whereFieldNames = QStringList());
0143 
0144     friend class KDbConnection;
0145 
0146 private:
0147 //! @todo is this portable across backends?
0148     bool generateStatementString(KDbEscapedString* s);
0149     bool generateSelectStatementString(KDbEscapedString * s);
0150     bool generateInsertStatementString(KDbEscapedString * s);
0151 
0152     QSharedDataPointer<Data> d;
0153 };
0154 
0155 #endif