File indexing completed on 2024-12-08 12:45:01
0001 /* This file is part of the KDE project 0002 Copyright (C) 2003-2016 Jarosław Staniek <staniek@kde.org> 0003 0004 This program 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 program 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 program; see the file COPYING. 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_CURSOR_H 0021 #define KDB_CURSOR_H 0022 0023 #include <QString> 0024 #include <QVariant> 0025 0026 #include "KDbResult.h" 0027 #include "KDbQueryColumnInfo.h" 0028 0029 class KDbConnection; 0030 class KDbRecordData; 0031 class KDbQuerySchema; 0032 class KDbRecordEditBuffer; 0033 0034 //! Provides database cursor functionality. 0035 /*! 0036 Cursor can be defined in two ways: 0037 0038 -# by passing KDbQuerySchema object to KDbConnection::executeQuery() or KDbConnection::prepareQuery(); 0039 then query is defined for in engine-independent way -- this is recommended usage 0040 0041 -# by passing raw query statement string to KDbConnection::executeQuery() or KDbConnection::prepareQuery(); 0042 then query may be defined for in engine-dependent way -- this is not recommended usage, 0043 but convenient when we can't or do not want to allocate KDbQuerySchema object, while we 0044 know that the query statement is syntactically and logically ok in our context. 0045 0046 You can move cursor to next record with moveNext() and move back with movePrev(). 0047 The cursor is always positioned on record, not between records, with exception that 0048 after open() it is positioned before the first record (if any) -- then bof() equals true. 0049 The cursor can also be positioned after the last record (if any) with moveNext() -- then eof() equals true. 0050 For example, if you have four records, 1, 2, 3, 4, then after calling open(), moveNext(), 0051 moveNext(), moveNext(), movePrev() you are going through records: 1, 2, 3, 2. 0052 0053 Cursor can be buffered or unbuferred. 0054 0055 @warning Buffered cursors are not implemented! 0056 0057 Buffering in this class is not related to any SQL engine capatibilities for server-side cursors 0058 (eg. like 'DECLARE CURSOR' statement) - buffered data is at client (application) side. 0059 Any record retrieved in buffered cursor will be stored inside an internal buffer 0060 and reused when needed. Unbuffered cursor always requires one record fetching from 0061 db connection at every step done with moveNext(), movePrev(), etc. 0062 0063 Notes: 0064 - Do not use delete operator for KDbCursor objects - this will fail; use KDbConnection::deleteCursor() 0065 instead. 0066 - KDbQuerySchema object is not owned by KDbCursor object that uses it. 0067 */ 0068 class KDB_EXPORT KDbCursor: public KDbResultable 0069 { 0070 Q_DECLARE_TR_FUNCTIONS(KDbCursor) 0071 public: 0072 //! Options that describe behavior of database cursor 0073 enum class Option { 0074 None = 0, 0075 Buffered = 1 0076 }; 0077 Q_DECLARE_FLAGS(Options, Option) 0078 0079 /*! @return connection used for the cursor */ 0080 KDbConnection* connection(); 0081 0082 //! @overload 0083 //! @since 3.1 0084 const KDbConnection* connection() const; 0085 0086 /*! Opens the cursor using data provided on creation. 0087 The data might be either KDbQuerySchema or a raw SQL statement. */ 0088 bool open(); 0089 0090 /*! Closes and then opens again the same cursor. 0091 If the cursor is not opened it is just opened and result of this open is returned. 0092 Otherwise, true is returned if cursor is successfully closed and then opened. */ 0093 bool reopen(); 0094 0095 /*! Closes previously opened cursor. 0096 If the cursor is closed, nothing happens. */ 0097 virtual bool close(); 0098 0099 /*! @return query schema used to define this cursor 0100 or 0 if the cursor is not defined by a query schema but by a raw SQL statement. */ 0101 KDbQuerySchema *query() const; 0102 0103 //! @return query parameters assigned to this cursor 0104 QList<QVariant> queryParameters() const; 0105 0106 //! Sets query parameters @a params for this cursor. 0107 void setQueryParameters(const QList<QVariant>& params); 0108 0109 /*! @return raw query statement used to define this cursor 0110 or null string if raw statement instead (but KDbQuerySchema is defined instead). */ 0111 KDbEscapedString rawSql() const; 0112 0113 /*! @return cursor options */ 0114 Options options() const; 0115 0116 /*! @return true if the cursor is opened. */ 0117 bool isOpened() const; 0118 0119 /*! @return true if the cursor is buffered. */ 0120 bool isBuffered() const; 0121 0122 /*! Sets this cursor to buffered type or not. See description 0123 of buffered and nonbuffered cursors in class description. 0124 This method only works if cursor is not opened (isOpened()==false). 0125 You can close already opened cursor and then switch this option on/off. 0126 */ 0127 void setBuffered(bool buffered); 0128 0129 /*! Moves current position to the first record and retrieves it. 0130 @return true if the first record was retrieved. 0131 False could mean that there was an error or there is no record available. */ 0132 bool moveFirst(); 0133 0134 /*! Moves current position to the last record and retrieves it. 0135 @return true if the last record was retrieved. 0136 False could mean that there was an error or there is no record available. */ 0137 virtual bool moveLast(); 0138 0139 /*! Moves current position to the next record and retrieves it. */ 0140 virtual bool moveNext(); 0141 0142 /*! Moves current position to the next record and retrieves it. 0143 Currently it's only supported for buffered cursors. */ 0144 virtual bool movePrev(); 0145 0146 /*! @return true if current position is after last record. */ 0147 inline bool eof() const { 0148 return m_afterLast; 0149 } 0150 0151 /*! @return true if current position is before first record. */ 0152 inline bool bof() const { 0153 return m_at == 0; 0154 } 0155 0156 /*! @return current internal position of the cursor's query. 0157 We are counting records from 0. 0158 Value -1 means that cursor does not point to any valid record 0159 (this happens eg. after open(), close(), 0160 and after moving after last record or before first one. */ 0161 inline qint64 at() const { 0162 return readAhead() ? 0 : (m_at - 1); 0163 } 0164 0165 /*! @return number of fields available for this cursor. 0166 This never includes ROWID column or other internal columns (e.g. lookup). */ 0167 inline int fieldCount() const { 0168 return m_query ? m_logicalFieldCount : m_fieldCount; 0169 } 0170 0171 /*! @return true if ROWID information is available for each record. 0172 ROWID information is available 0173 if KDbDriverBehavior::ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE == false 0174 for a KDb database driver and the master table has no primary key defined. 0175 Phisically, ROWID value is returned after last returned field, 0176 so data vector's length is expanded by one. */ 0177 bool containsRecordIdInfo() const; 0178 0179 /*! @return a value stored in column number @a i (counting from 0). 0180 It has unspecified behavior if the cursor is not at valid record. 0181 Note for driver developers: 0182 If @a i is >= than m_fieldCount, null QVariant value should be returned. 0183 To return a value typically you can use a pointer to internal structure 0184 that contain current record data (buffered or unbuffered). */ 0185 virtual QVariant value(int i) = 0; 0186 0187 /*! [PROTOTYPE] @return current record data or @c nullptr if there is no current records. */ 0188 virtual const char ** recordData() const = 0; 0189 0190 /*! Sets a list of columns for ORDER BY section of the query. 0191 Only works when the cursor has been created using KDbQuerySchema object 0192 (i.e. when query()!=0; does not work with raw statements). 0193 Each name on the list must be a field or alias present within the query 0194 and must not be covered by aliases. If one or more names cannot be found within 0195 the query, the method will have no effect. Any previous ORDER BY settings will be removed. 0196 0197 The order list provided here has priority over a list defined in the KDbQuerySchema 0198 object itseld (using KDbQuerySchema::setOrderByColumnList()). 0199 The KDbQuerySchema object itself is not modifed by this method: only order of records retrieved 0200 by this cursor is affected. 0201 0202 Use this method before calling open(). You can also call reopen() after calling this method 0203 to see effects of applying records order. */ 0204 //! @todo implement this 0205 void setOrderByColumnList(const QStringList& columnNames); 0206 0207 /*! Convenience method, similar to setOrderByColumnList(const QStringList&). */ 0208 //! @todo implement this 0209 void setOrderByColumnList(const QString& column1, const QString& column2 = QString(), 0210 const QString& column3 = QString(), const QString& column4 = QString(), 0211 const QString& column5 = QString()); 0212 0213 /*! @return a list of fields contained in ORDER BY section of the query. 0214 @see setOrderBy(const QStringList&) */ 0215 KDbQueryColumnInfo::Vector orderByColumnList() const; 0216 0217 /*! Allocates a new KDbRecordData and stores data in it (makes a deep copy of each field). 0218 If the cursor is not at valid record, the result is undefined. 0219 @return newly created record data object or 0 on error. */ 0220 KDbRecordData* storeCurrentRecord() const; 0221 0222 /*! Puts current record's data into @a data (makes a deep copy of each field). 0223 If the cursor is not at valid record, the result is undefined. 0224 @return true on success. 0225 @c false is returned if @a data is @c nullptr. */ 0226 bool storeCurrentRecord(KDbRecordData* data) const; 0227 0228 bool updateRecord(KDbRecordData* data, KDbRecordEditBuffer* buf, bool useRecordId = false); 0229 0230 bool insertRecord(KDbRecordData* data, KDbRecordEditBuffer* buf, bool getRecrordId = false); 0231 0232 bool deleteRecord(KDbRecordData* data, bool useRecordId = false); 0233 0234 bool deleteAllRecords(); 0235 0236 protected: 0237 /*! Cursor will operate on @a conn, raw SQL statement @a sql will be used to execute query. */ 0238 KDbCursor(KDbConnection* conn, const KDbEscapedString& sql, Options options = KDbCursor::Option::None); 0239 0240 /*! Cursor will operate on @a conn, @a query schema will be used to execute query. */ 0241 KDbCursor(KDbConnection* conn, KDbQuerySchema* query, Options options = KDbCursor::Option::None); 0242 0243 ~KDbCursor() override; 0244 0245 void init(KDbConnection* conn); 0246 0247 /*! Internal: cares about proper flag setting depending on result of drv_getNextRecord() 0248 and depending on wherher a cursor is buffered. */ 0249 bool getNextRecord(); 0250 0251 /*! Note for driver developers: this method should initialize engine-specific cursor's 0252 resources using an SQL statement @a sql. It is not required to store @a sql statement somewhere 0253 in your KDbCursor subclass (it is already stored in m_query or m_rawStatement, 0254 depending query type) - only pass it to proper engine's function. */ 0255 virtual bool drv_open(const KDbEscapedString& sql) = 0; 0256 0257 virtual bool drv_close() = 0; 0258 virtual void drv_getNextRecord() = 0; 0259 0260 /*! Stores currently fetched record's values in appropriate place of the buffer. 0261 Note for driver developers: 0262 This place can be computed using m_at. Do not change value of m_at or any other 0263 KDbCursor members, only change your internal structures like pointer to current 0264 record, etc. If your database engine's API function (for record fetching) 0265 do not allocates such a space, you want to allocate a space for current 0266 record. Otherwise, reuse existing structure, what could be more efficient. 0267 All functions like drv_appendCurrentRecordToBuffer() operates on the buffer, 0268 i.e. array of stored records. You are not forced to have any particular 0269 fixed structure for buffer item or buffer itself - the structure is internal and 0270 only methods like storeCurrentRecord() visible to public. 0271 */ 0272 virtual void drv_appendCurrentRecordToBuffer() = 0; 0273 /*! Moves pointer (that points to the buffer) -- to next item in this buffer. 0274 Note for driver developers: probably just execute "your_pointer++" is enough. 0275 */ 0276 virtual void drv_bufferMovePointerNext() = 0; 0277 /*! Like drv_bufferMovePointerNext() but execute "your_pointer--". */ 0278 virtual void drv_bufferMovePointerPrev() = 0; 0279 /*! Moves pointer (that points to the buffer) to a new place: @a at. 0280 */ 0281 virtual void drv_bufferMovePointerTo(qint64 at) = 0; 0282 0283 /*! Clears cursor's buffer if this was allocated (only for buffered cursor type). 0284 Otherwise do nothing. For reimplementing. Default implementation does nothing. */ 0285 virtual void drv_clearBuffer() {} 0286 0287 //! @internal clears buffer with reimplemented drv_clearBuffer(). */ 0288 void clearBuffer(); 0289 0290 /*! Puts current record's data into @a data (makes a deep copy of each field). 0291 This method has unspecified behavior if the cursor is not at valid record. 0292 @return true on success. 0293 Note: For reimplementation in driver's code. Shortly, this method translates 0294 a record data from internal representation (probably also used in buffer) 0295 to simple public KDbRecordData representation. */ 0296 virtual bool drv_storeCurrentRecord(KDbRecordData* data) const = 0; 0297 0298 KDbQuerySchema *m_query; 0299 bool m_afterLast; 0300 qint64 m_at; 0301 int m_fieldCount; //!< cached field count information 0302 int m_fieldsToStoreInRecord; //!< Used by storeCurrentRecord(), reimplement if needed 0303 //!< (e.g. PostgreSQL driver, when m_containsRecordIdInfo is true 0304 //!< sets m_fieldCount+1 here) 0305 int m_logicalFieldCount; //!< logical field count, i.e. without internal values like Record Id or lookup 0306 KDbCursor::Options m_options; //!< cursor options that describes its behavior 0307 0308 //! Possible results of record fetching, used for m_fetchResult 0309 enum class FetchResult { 0310 Invalid, //!< used before starting the fetching, result is not known yet 0311 Error, //!< error of fetching 0312 Ok, //!< the data is fetched 0313 End //!< at the end of data 0314 }; 0315 0316 FetchResult m_fetchResult; //!< result of a record fetching 0317 0318 //<members related to buffering> 0319 int m_records_in_buf; //!< number of records currently stored in the buffer 0320 bool m_buffering_completed; //!< true if we already have all records stored in the buffer 0321 //</members related to buffering> 0322 0323 //! Useful e.g. for value(int) method to obtain access to schema definition. 0324 KDbQueryColumnInfo::Vector* m_visibleFieldsExpanded; 0325 0326 private: 0327 bool readAhead() const; 0328 0329 Q_DISABLE_COPY(KDbCursor) 0330 friend class CursorDeleter; 0331 class Private; 0332 Private * const d; 0333 }; 0334 0335 //! Sends information about object @a cursor to debug output @a dbg. 0336 //! @since 3.1 0337 KDB_EXPORT QDebug operator<<(QDebug dbg, KDbCursor& cursor); 0338 0339 //! Sends information about object @a cursor to debug output @a dbg. 0340 KDB_EXPORT QDebug operator<<(QDebug dbg, const KDbCursor& cursor); 0341 0342 Q_DECLARE_OPERATORS_FOR_FLAGS(KDbCursor::Options) 0343 0344 #endif