File indexing completed on 2024-04-14 04:35:42

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