KDb

KDbCursor.h
1 /* This file is part of the KDE project
2  Copyright (C) 2003-2016 JarosÅ‚aw Staniek <[email protected]>
3 
4  This program is free software; you can redistribute it and/or
5  modify it under the terms of the GNU Library General Public
6  License as published by the Free Software Foundation; either
7  version 2 of the License, or (at your option) any later version.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12  Library General Public License for more details.
13 
14  You should have received a copy of the GNU Library General Public License
15  along with this program; see the file COPYING. If not, write to
16  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18 */
19 
20 #ifndef KDB_CURSOR_H
21 #define KDB_CURSOR_H
22 
23 #include <QString>
24 #include <QVariant>
25 
26 #include "KDbResult.h"
27 #include "KDbQueryColumnInfo.h"
28 
29 class KDbConnection;
30 class KDbRecordData;
31 class KDbQuerySchema;
33 
34 //! Provides database cursor functionality.
35 /*!
36  Cursor can be defined in two ways:
37 
38  -# by passing KDbQuerySchema object to KDbConnection::executeQuery() or KDbConnection::prepareQuery();
39  then query is defined for in engine-independent way -- this is recommended usage
40 
41  -# by passing raw query statement string to KDbConnection::executeQuery() or KDbConnection::prepareQuery();
42  then query may be defined for in engine-dependent way -- this is not recommended usage,
43  but convenient when we can't or do not want to allocate KDbQuerySchema object, while we
44  know that the query statement is syntactically and logically ok in our context.
45 
46  You can move cursor to next record with moveNext() and move back with movePrev().
47  The cursor is always positioned on record, not between records, with exception that
48  after open() it is positioned before the first record (if any) -- then bof() equals true.
49  The cursor can also be positioned after the last record (if any) with moveNext() -- then eof() equals true.
50  For example, if you have four records, 1, 2, 3, 4, then after calling open(), moveNext(),
51  moveNext(), moveNext(), movePrev() you are going through records: 1, 2, 3, 2.
52 
53  Cursor can be buffered or unbuferred.
54 
55  @warning Buffered cursors are not implemented!
56 
57  Buffering in this class is not related to any SQL engine capatibilities for server-side cursors
58  (eg. like 'DECLARE CURSOR' statement) - buffered data is at client (application) side.
59  Any record retrieved in buffered cursor will be stored inside an internal buffer
60  and reused when needed. Unbuffered cursor always requires one record fetching from
61  db connection at every step done with moveNext(), movePrev(), etc.
62 
63  Notes:
64  - Do not use delete operator for KDbCursor objects - this will fail; use KDbConnection::deleteCursor()
65  instead.
66  - KDbQuerySchema object is not owned by KDbCursor object that uses it.
67 */
68 class KDB_EXPORT KDbCursor: public KDbResultable
69 {
70  Q_DECLARE_TR_FUNCTIONS(KDbCursor)
71 public:
72  //! Options that describe behavior of database cursor
73  enum class Option {
74  None = 0,
75  Buffered = 1
76  };
77  Q_DECLARE_FLAGS(Options, Option)
78 
79  /*! @return connection used for the cursor */
80  KDbConnection* connection();
81 
82  //! @overload
83  //! @since 3.1
84  const KDbConnection* connection() const;
85 
86  /*! Opens the cursor using data provided on creation.
87  The data might be either KDbQuerySchema or a raw SQL statement. */
88  bool open();
89 
90  /*! Closes and then opens again the same cursor.
91  If the cursor is not opened it is just opened and result of this open is returned.
92  Otherwise, true is returned if cursor is successfully closed and then opened. */
93  bool reopen();
94 
95  /*! Closes previously opened cursor.
96  If the cursor is closed, nothing happens. */
97  virtual bool close();
98 
99  /*! @return query schema used to define this cursor
100  or 0 if the cursor is not defined by a query schema but by a raw SQL statement. */
101  KDbQuerySchema *query() const;
102 
103  //! @return query parameters assigned to this cursor
104  QList<QVariant> queryParameters() const;
105 
106  //! Sets query parameters @a params for this cursor.
107  void setQueryParameters(const QList<QVariant>& params);
108 
109  /*! @return raw query statement used to define this cursor
110  or null string if raw statement instead (but KDbQuerySchema is defined instead). */
111  KDbEscapedString rawSql() const;
112 
113  /*! @return cursor options */
114  Options options() const;
115 
116  /*! @return true if the cursor is opened. */
117  bool isOpened() const;
118 
119  /*! @return true if the cursor is buffered. */
120  bool isBuffered() const;
121 
122  /*! Sets this cursor to buffered type or not. See description
123  of buffered and nonbuffered cursors in class description.
124  This method only works if cursor is not opened (isOpened()==false).
125  You can close already opened cursor and then switch this option on/off.
126  */
127  void setBuffered(bool buffered);
128 
129  /*! Moves current position to the first record and retrieves it.
130  @return true if the first record was retrieved.
131  False could mean that there was an error or there is no record available. */
132  bool moveFirst();
133 
134  /*! Moves current position to the last record and retrieves it.
135  @return true if the last record was retrieved.
136  False could mean that there was an error or there is no record available. */
137  virtual bool moveLast();
138 
139  /*! Moves current position to the next record and retrieves it. */
140  virtual bool moveNext();
141 
142  /*! Moves current position to the next record and retrieves it.
143  Currently it's only supported for buffered cursors. */
144  virtual bool movePrev();
145 
146  /*! @return true if current position is after last record. */
147  inline bool eof() const {
148  return m_afterLast;
149  }
150 
151  /*! @return true if current position is before first record. */
152  inline bool bof() const {
153  return m_at == 0;
154  }
155 
156  /*! @return current internal position of the cursor's query.
157  We are counting records from 0.
158  Value -1 means that cursor does not point to any valid record
159  (this happens eg. after open(), close(),
160  and after moving after last record or before first one. */
161  inline qint64 at() const {
162  return readAhead() ? 0 : (m_at - 1);
163  }
164 
165  /*! @return number of fields available for this cursor.
166  This never includes ROWID column or other internal columns (e.g. lookup). */
167  inline int fieldCount() const {
168  return m_query ? m_logicalFieldCount : m_fieldCount;
169  }
170 
171  /*! @return true if ROWID information is available for each record.
172  ROWID information is available
173  if KDbDriverBehavior::ROW_ID_FIELD_RETURNS_LAST_AUTOINCREMENTED_VALUE == false
174  for a KDb database driver and the master table has no primary key defined.
175  Phisically, ROWID value is returned after last returned field,
176  so data vector's length is expanded by one. */
177  bool containsRecordIdInfo() const;
178 
179  /*! @return a value stored in column number @a i (counting from 0).
180  It has unspecified behavior if the cursor is not at valid record.
181  Note for driver developers:
182  If @a i is >= than m_fieldCount, null QVariant value should be returned.
183  To return a value typically you can use a pointer to internal structure
184  that contain current record data (buffered or unbuffered). */
185  virtual QVariant value(int i) = 0;
186 
187  /*! [PROTOTYPE] @return current record data or @c nullptr if there is no current records. */
188  virtual const char ** recordData() const = 0;
189 
190  /*! Sets a list of columns for ORDER BY section of the query.
191  Only works when the cursor has been created using KDbQuerySchema object
192  (i.e. when query()!=0; does not work with raw statements).
193  Each name on the list must be a field or alias present within the query
194  and must not be covered by aliases. If one or more names cannot be found within
195  the query, the method will have no effect. Any previous ORDER BY settings will be removed.
196 
197  The order list provided here has priority over a list defined in the KDbQuerySchema
198  object itseld (using KDbQuerySchema::setOrderByColumnList()).
199  The KDbQuerySchema object itself is not modifed by this method: only order of records retrieved
200  by this cursor is affected.
201 
202  Use this method before calling open(). You can also call reopen() after calling this method
203  to see effects of applying records order. */
204  //! @todo implement this
205  void setOrderByColumnList(const QStringList& columnNames);
206 
207  /*! Convenience method, similar to setOrderByColumnList(const QStringList&). */
208  //! @todo implement this
209  void setOrderByColumnList(const QString& column1, const QString& column2 = QString(),
210  const QString& column3 = QString(), const QString& column4 = QString(),
211  const QString& column5 = QString());
212 
213  /*! @return a list of fields contained in ORDER BY section of the query.
214  @see setOrderBy(const QStringList&) */
215  KDbQueryColumnInfo::Vector orderByColumnList() const;
216 
217  /*! Allocates a new KDbRecordData and stores data in it (makes a deep copy of each field).
218  If the cursor is not at valid record, the result is undefined.
219  @return newly created record data object or 0 on error. */
220  KDbRecordData* storeCurrentRecord() const;
221 
222  /*! Puts current record's data into @a data (makes a deep copy of each field).
223  If the cursor is not at valid record, the result is undefined.
224  @return true on success.
225  @c false is returned if @a data is @c nullptr. */
226  bool storeCurrentRecord(KDbRecordData* data) const;
227 
228  bool updateRecord(KDbRecordData* data, KDbRecordEditBuffer* buf, bool useRecordId = false);
229 
230  bool insertRecord(KDbRecordData* data, KDbRecordEditBuffer* buf, bool getRecrordId = false);
231 
232  bool deleteRecord(KDbRecordData* data, bool useRecordId = false);
233 
234  bool deleteAllRecords();
235 
236 protected:
237  /*! Cursor will operate on @a conn, raw SQL statement @a sql will be used to execute query. */
238  KDbCursor(KDbConnection* conn, const KDbEscapedString& sql, Options options = KDbCursor::Option::None);
239 
240  /*! Cursor will operate on @a conn, @a query schema will be used to execute query. */
241  KDbCursor(KDbConnection* conn, KDbQuerySchema* query, Options options = KDbCursor::Option::None);
242 
243  ~KDbCursor() override;
244 
245  void init(KDbConnection* conn);
246 
247  /*! Internal: cares about proper flag setting depending on result of drv_getNextRecord()
248  and depending on wherher a cursor is buffered. */
249  bool getNextRecord();
250 
251  /*! Note for driver developers: this method should initialize engine-specific cursor's
252  resources using an SQL statement @a sql. It is not required to store @a sql statement somewhere
253  in your KDbCursor subclass (it is already stored in m_query or m_rawStatement,
254  depending query type) - only pass it to proper engine's function. */
255  virtual bool drv_open(const KDbEscapedString& sql) = 0;
256 
257  virtual bool drv_close() = 0;
258  virtual void drv_getNextRecord() = 0;
259 
260  /*! Stores currently fetched record's values in appropriate place of the buffer.
261  Note for driver developers:
262  This place can be computed using m_at. Do not change value of m_at or any other
263  KDbCursor members, only change your internal structures like pointer to current
264  record, etc. If your database engine's API function (for record fetching)
265  do not allocates such a space, you want to allocate a space for current
266  record. Otherwise, reuse existing structure, what could be more efficient.
267  All functions like drv_appendCurrentRecordToBuffer() operates on the buffer,
268  i.e. array of stored records. You are not forced to have any particular
269  fixed structure for buffer item or buffer itself - the structure is internal and
270  only methods like storeCurrentRecord() visible to public.
271  */
272  virtual void drv_appendCurrentRecordToBuffer() = 0;
273  /*! Moves pointer (that points to the buffer) -- to next item in this buffer.
274  Note for driver developers: probably just execute "your_pointer++" is enough.
275  */
276  virtual void drv_bufferMovePointerNext() = 0;
277  /*! Like drv_bufferMovePointerNext() but execute "your_pointer--". */
278  virtual void drv_bufferMovePointerPrev() = 0;
279  /*! Moves pointer (that points to the buffer) to a new place: @a at.
280  */
281  virtual void drv_bufferMovePointerTo(qint64 at) = 0;
282 
283  /*! Clears cursor's buffer if this was allocated (only for buffered cursor type).
284  Otherwise do nothing. For reimplementing. Default implementation does nothing. */
285  virtual void drv_clearBuffer() {}
286 
287  //! @internal clears buffer with reimplemented drv_clearBuffer(). */
288  void clearBuffer();
289 
290  /*! Puts current record's data into @a data (makes a deep copy of each field).
291  This method has unspecified behavior if the cursor is not at valid record.
292  @return true on success.
293  Note: For reimplementation in driver's code. Shortly, this method translates
294  a record data from internal representation (probably also used in buffer)
295  to simple public KDbRecordData representation. */
296  virtual bool drv_storeCurrentRecord(KDbRecordData* data) const = 0;
297 
298  KDbQuerySchema *m_query;
299  bool m_afterLast;
300  qint64 m_at;
301  int m_fieldCount; //!< cached field count information
302  int m_fieldsToStoreInRecord; //!< Used by storeCurrentRecord(), reimplement if needed
303  //!< (e.g. PostgreSQL driver, when m_containsRecordIdInfo is true
304  //!< sets m_fieldCount+1 here)
305  int m_logicalFieldCount; //!< logical field count, i.e. without internal values like Record Id or lookup
306  KDbCursor::Options m_options; //!< cursor options that describes its behavior
307 
308  //! Possible results of record fetching, used for m_fetchResult
309  enum class FetchResult {
310  Invalid, //!< used before starting the fetching, result is not known yet
311  Error, //!< error of fetching
312  Ok, //!< the data is fetched
313  End //!< at the end of data
314  };
315 
316  FetchResult m_fetchResult; //!< result of a record fetching
317 
318  //<members related to buffering>
319  int m_records_in_buf; //!< number of records currently stored in the buffer
320  bool m_buffering_completed; //!< true if we already have all records stored in the buffer
321  //</members related to buffering>
322 
323  //! Useful e.g. for value(int) method to obtain access to schema definition.
325 
326 private:
327  bool readAhead() const;
328 
329  Q_DISABLE_COPY(KDbCursor)
330  friend class CursorDeleter;
331  class Private;
332  Private * const d;
333 };
334 
335 //! Sends information about object @a cursor to debug output @a dbg.
336 //! @since 3.1
337 KDB_EXPORT QDebug operator<<(QDebug dbg, KDbCursor& cursor);
338 
339 //! Sends information about object @a cursor to debug output @a dbg.
340 KDB_EXPORT QDebug operator<<(QDebug dbg, const KDbCursor& cursor);
341 
342 Q_DECLARE_OPERATORS_FOR_FLAGS(KDbCursor::Options)
343 
344 #endif
Provides database cursor functionality.
Definition: KDbCursor.h:68
FetchResult m_fetchResult
result of a record fetching
Definition: KDbCursor.h:316
QCA_EXPORT void init()
int fieldCount() const
Definition: KDbCursor.h:167
Specialized string for escaping.
QDataStream & operator<<(QDataStream &out, const KDateTime &dateTime)
FetchResult
Possible results of record fetching, used for m_fetchResult.
Definition: KDbCursor.h:309
bool eof() const
Definition: KDbCursor.h:147
Interface for classes providing a result.
KDbQueryColumnInfo::Vector * m_visibleFieldsExpanded
Useful e.g. for value(int) method to obtain access to schema definition.
Definition: KDbCursor.h:324
int m_records_in_buf
number of records currently stored in the buffer
Definition: KDbCursor.h:319
provides data for single edited database record
virtual void drv_clearBuffer()
Definition: KDbCursor.h:285
bool bof() const
Definition: KDbCursor.h:152
bool m_buffering_completed
true if we already have all records stored in the buffer
Definition: KDbCursor.h:320
Structure for storing single record with type information.
Definition: KDbRecordData.h:36
Option
Options that describe behavior of database cursor.
Definition: KDbCursor.h:73
KDbQuerySchema provides information about database query.
int m_logicalFieldCount
logical field count, i.e. without internal values like Record Id or lookup
Definition: KDbCursor.h:305
Provides database connection, allowing queries and data modification.
Definition: KDbConnection.h:51
qint64 at() const
Definition: KDbCursor.h:161
int m_fieldCount
cached field count information
Definition: KDbCursor.h:301
int m_fieldsToStoreInRecord
Used by storeCurrentRecord(), reimplement if needed.
Definition: KDbCursor.h:302
KDbCursor::Options m_options
cursor options that describes its behavior
Definition: KDbCursor.h:306
This file is part of the KDE documentation.
Documentation copyright © 1996-2022 The KDE developers.
Generated on Sat Jun 25 2022 06:21:33 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.