File indexing completed on 2024-12-01 04:19:12
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