1 | /****************************************************************************
|
---|
2 | **
|
---|
3 | ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
|
---|
4 | ** All rights reserved.
|
---|
5 | ** Contact: Nokia Corporation (qt-info@nokia.com)
|
---|
6 | **
|
---|
7 | ** This file is part of the Qt3Support module of the Qt Toolkit.
|
---|
8 | **
|
---|
9 | ** $QT_BEGIN_LICENSE:LGPL$
|
---|
10 | ** Commercial Usage
|
---|
11 | ** Licensees holding valid Qt Commercial licenses may use this file in
|
---|
12 | ** accordance with the Qt Commercial License Agreement provided with the
|
---|
13 | ** Software or, alternatively, in accordance with the terms contained in
|
---|
14 | ** a written agreement between you and Nokia.
|
---|
15 | **
|
---|
16 | ** GNU Lesser General Public License Usage
|
---|
17 | ** Alternatively, this file may be used under the terms of the GNU Lesser
|
---|
18 | ** General Public License version 2.1 as published by the Free Software
|
---|
19 | ** Foundation and appearing in the file LICENSE.LGPL included in the
|
---|
20 | ** packaging of this file. Please review the following information to
|
---|
21 | ** ensure the GNU Lesser General Public License version 2.1 requirements
|
---|
22 | ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
---|
23 | **
|
---|
24 | ** In addition, as a special exception, Nokia gives you certain additional
|
---|
25 | ** rights. These rights are described in the Nokia Qt LGPL Exception
|
---|
26 | ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
---|
27 | **
|
---|
28 | ** GNU General Public License Usage
|
---|
29 | ** Alternatively, this file may be used under the terms of the GNU
|
---|
30 | ** General Public License version 3.0 as published by the Free Software
|
---|
31 | ** Foundation and appearing in the file LICENSE.GPL included in the
|
---|
32 | ** packaging of this file. Please review the following information to
|
---|
33 | ** ensure the GNU General Public License version 3.0 requirements will be
|
---|
34 | ** met: http://www.gnu.org/copyleft/gpl.html.
|
---|
35 | **
|
---|
36 | ** If you have questions regarding the use of this file, please contact
|
---|
37 | ** Nokia at qt-info@nokia.com.
|
---|
38 | ** $QT_END_LICENSE$
|
---|
39 | **
|
---|
40 | ****************************************************************************/
|
---|
41 |
|
---|
42 | #include <qplatformdefs.h>
|
---|
43 | #include "q3sqlcursor.h"
|
---|
44 |
|
---|
45 | #ifndef QT_NO_SQL
|
---|
46 |
|
---|
47 | #include "qsqldriver.h"
|
---|
48 | #include "qsqlresult.h"
|
---|
49 | #include "qdatetime.h"
|
---|
50 | #include "qsqldatabase.h"
|
---|
51 | #include "qsql.h"
|
---|
52 | #include "q3sqlrecordinfo.h"
|
---|
53 | #include "q3sqlfieldinfo.h"
|
---|
54 |
|
---|
55 | QT_BEGIN_NAMESPACE
|
---|
56 |
|
---|
57 | class Q3SqlCursorPrivate
|
---|
58 | {
|
---|
59 | public:
|
---|
60 |
|
---|
61 | Q3SqlCursorPrivate(const QString& name, QSqlDatabase sdb)
|
---|
62 | : lastAt(QSql::BeforeFirst), nm(name), srt(name), md(0), db(sdb), q(0)
|
---|
63 | {}
|
---|
64 | ~Q3SqlCursorPrivate()
|
---|
65 | {
|
---|
66 | delete q;
|
---|
67 | }
|
---|
68 |
|
---|
69 | QSqlQuery* query()
|
---|
70 | {
|
---|
71 | if (!q)
|
---|
72 | q = new QSqlQuery(QString(), db);
|
---|
73 | return q;
|
---|
74 | }
|
---|
75 |
|
---|
76 | int lastAt;
|
---|
77 | QString nm; //name
|
---|
78 | QSqlIndex srt; //sort
|
---|
79 | QString ftr; //filter
|
---|
80 | int md; //mode
|
---|
81 | QSqlIndex priIndx; //primary index
|
---|
82 | QSqlRecord editBuffer;
|
---|
83 | // the primary index as it was before the user changed the values in editBuffer
|
---|
84 | QString editIndex;
|
---|
85 | Q3SqlRecordInfo infoBuffer;
|
---|
86 | QSqlDatabase db;
|
---|
87 | QSqlQuery *q;
|
---|
88 | };
|
---|
89 |
|
---|
90 | QString qOrderByClause(const QSqlIndex & i, const QString& prefix = QString())
|
---|
91 | {
|
---|
92 | QString str;
|
---|
93 | int k = i.count();
|
---|
94 | if(k == 0)
|
---|
95 | return QString();
|
---|
96 | str = QLatin1String(" order by ") + i.toString(prefix);
|
---|
97 | return str;
|
---|
98 | }
|
---|
99 |
|
---|
100 | QString qWhereClause(const QString& prefix, QSqlField* field, const QSqlDriver* driver)
|
---|
101 | {
|
---|
102 | QString f;
|
---|
103 | if (field && driver) {
|
---|
104 | if (!prefix.isEmpty())
|
---|
105 | f += prefix + QLatin1Char('.');
|
---|
106 | f += field->name();
|
---|
107 | if (field->isNull()) {
|
---|
108 | f += QLatin1String(" IS NULL");
|
---|
109 | } else {
|
---|
110 | f += QLatin1String(" = ") + driver->formatValue(field);
|
---|
111 | }
|
---|
112 | }
|
---|
113 | return f;
|
---|
114 | }
|
---|
115 |
|
---|
116 | QString qWhereClause(QSqlRecord* rec, const QString& prefix, const QString& sep,
|
---|
117 | const QSqlDriver* driver)
|
---|
118 | {
|
---|
119 | static QString blank(QLatin1Char(' '));
|
---|
120 | QString filter;
|
---|
121 | bool separator = false;
|
---|
122 | for (int j = 0; j < rec->count(); ++j) {
|
---|
123 | QSqlField f = rec->field(j);
|
---|
124 | if (rec->isGenerated(j)) {
|
---|
125 | if (separator)
|
---|
126 | filter += sep + blank;
|
---|
127 | filter += qWhereClause(prefix, &f, driver);
|
---|
128 | filter += blank;
|
---|
129 | separator = true;
|
---|
130 | }
|
---|
131 | }
|
---|
132 | return filter;
|
---|
133 | }
|
---|
134 |
|
---|
135 | /*!
|
---|
136 | \class Q3SqlCursor
|
---|
137 | \brief The Q3SqlCursor class provides browsing and editing of SQL
|
---|
138 | tables and views.
|
---|
139 |
|
---|
140 | \compat
|
---|
141 |
|
---|
142 | A Q3SqlCursor is a database record (see \l QSqlRecord) that
|
---|
143 | corresponds to a table or view within an SQL database (see \l
|
---|
144 | QSqlDatabase). There are two buffers in a cursor, one used for
|
---|
145 | browsing and one used for editing records. Each buffer contains a
|
---|
146 | list of fields which correspond to the fields in the table or
|
---|
147 | view.
|
---|
148 |
|
---|
149 | When positioned on a valid record, the browse buffer contains the
|
---|
150 | values of the current record's fields from the database. The edit
|
---|
151 | buffer is separate, and is used for editing existing records and
|
---|
152 | inserting new records.
|
---|
153 |
|
---|
154 | For browsing data, a cursor must first select() data from the
|
---|
155 | database. After a successful select() the cursor is active
|
---|
156 | (isActive() returns true), but is initially not positioned on a
|
---|
157 | valid record (isValid() returns false). To position the cursor on
|
---|
158 | a valid record, use one of the navigation functions, next(),
|
---|
159 | previous(), first(), last(), or seek(). Once positioned on a valid
|
---|
160 | record, data can be retrieved from the browse buffer using
|
---|
161 | value(). If a navigation function is not successful, it returns
|
---|
162 | false, the cursor will no longer be positioned on a valid record
|
---|
163 | and the values returned by value() are undefined.
|
---|
164 |
|
---|
165 | For example:
|
---|
166 |
|
---|
167 | \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 0
|
---|
168 |
|
---|
169 | In the above example, a cursor is created specifying a table or
|
---|
170 | view name in the database. Then, select() is called, which can be
|
---|
171 | optionally parameterised to filter and order the records
|
---|
172 | retrieved. Each record in the cursor is retrieved using next().
|
---|
173 | When next() returns false, there are no more records to process,
|
---|
174 | and the loop terminates.
|
---|
175 |
|
---|
176 | For editing records (rows of data), a cursor contains a separate
|
---|
177 | edit buffer which is independent of the fields used when browsing.
|
---|
178 | The functions insert(), update() and del() operate on the edit
|
---|
179 | buffer. This allows the cursor to be repositioned to other
|
---|
180 | records while simultaneously maintaining a separate buffer for
|
---|
181 | edits. You can get a pointer to the edit buffer using
|
---|
182 | editBuffer(). The primeInsert(), primeUpdate() and primeDelete()
|
---|
183 | functions also return a pointer to the edit buffer and prepare it
|
---|
184 | for insert, update and delete respectively. Edit operations only
|
---|
185 | affect a single row at a time. Note that update() and del()
|
---|
186 | require that the table or view contain a primaryIndex() to ensure
|
---|
187 | that edit operations affect a unique record within the database.
|
---|
188 |
|
---|
189 | For example:
|
---|
190 |
|
---|
191 | \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 1
|
---|
192 |
|
---|
193 | To edit an existing database record, first move to the record you
|
---|
194 | wish to update. Call primeUpdate() to get the pointer to the
|
---|
195 | cursor's edit buffer. Then use this pointer to modify the values
|
---|
196 | in the edit buffer. Finally, call update() to save the changes to
|
---|
197 | the database. The values in the edit buffer will be used to
|
---|
198 | locate the appropriate record when updating the database (see
|
---|
199 | primaryIndex()).
|
---|
200 |
|
---|
201 | Similarly, when deleting an existing database record, first move
|
---|
202 | to the record you wish to delete. Then, call primeDelete() to get
|
---|
203 | the pointer to the edit buffer. Finally, call del() to delete the
|
---|
204 | record from the database. Again, the values in the edit buffer
|
---|
205 | will be used to locate and delete the appropriate record.
|
---|
206 |
|
---|
207 | To insert a new record, call primeInsert() to get the pointer to
|
---|
208 | the edit buffer. Use this pointer to populate the edit buffer
|
---|
209 | with new values and then insert() the record into the database.
|
---|
210 |
|
---|
211 | After calling insert(), update() or del(), the cursor is no longer
|
---|
212 | positioned on a valid record and can no longer be navigated
|
---|
213 | (isValid() return false). The reason for this is that any changes
|
---|
214 | made to the database will not be visible until select() is called
|
---|
215 | to refresh the cursor. You can change this behavior by passing
|
---|
216 | false to insert(), update() or del() which will prevent the cursor
|
---|
217 | from becoming invalid. The edits will still not be visible when
|
---|
218 | navigating the cursor until select() is called.
|
---|
219 |
|
---|
220 | Q3SqlCursor contains virtual methods which allow editing behavior
|
---|
221 | to be customized by subclasses. This allows custom cursors to be
|
---|
222 | created that encapsulate the editing behavior of a database table
|
---|
223 | for an entire application. For example, a cursor can be customized
|
---|
224 | to always auto-number primary index fields, or provide fields with
|
---|
225 | suitable default values, when inserting new records. Q3SqlCursor
|
---|
226 | generates SQL statements which are sent to the database engine;
|
---|
227 | you can control which fields are included in these statements
|
---|
228 | using setGenerated().
|
---|
229 |
|
---|
230 | Note that Q3SqlCursor does not inherit from QObject. This means
|
---|
231 | that you are responsible for destroying instances of this class
|
---|
232 | yourself. However if you create a Q3SqlCursor and use it in a
|
---|
233 | \l Q3DataTable, \l Q3DataBrowser or a \l Q3DataView these classes will
|
---|
234 | usually take ownership of the cursor and destroy it when they
|
---|
235 | don't need it anymore. The documentation for Q3DataTable,
|
---|
236 | Q3DataBrowser and Q3DataView explicitly states which calls take
|
---|
237 | ownership of the cursor.
|
---|
238 | */
|
---|
239 |
|
---|
240 | /*!
|
---|
241 | \enum Q3SqlCursor::Mode
|
---|
242 |
|
---|
243 | This enum type describes how Q3SqlCursor operates on records in the
|
---|
244 | database.
|
---|
245 |
|
---|
246 | \value ReadOnly the cursor can only SELECT records from the
|
---|
247 | database.
|
---|
248 |
|
---|
249 | \value Insert the cursor can INSERT records into the database.
|
---|
250 |
|
---|
251 | \value Update the cursor can UPDATE records in the database.
|
---|
252 |
|
---|
253 | \value Delete the cursor can DELETE records from the database.
|
---|
254 |
|
---|
255 | \value Writable the cursor can INSERT, UPDATE and DELETE records
|
---|
256 | in the database.
|
---|
257 | */
|
---|
258 |
|
---|
259 | /*!
|
---|
260 | \fn QVariant Q3SqlCursor::value(const QString &name) const
|
---|
261 |
|
---|
262 | \overload
|
---|
263 |
|
---|
264 | Returns the value of the field named \a name.
|
---|
265 | */
|
---|
266 |
|
---|
267 | /*!
|
---|
268 | \fn void Q3SqlCursor::setValue(const QString &name, const QVariant &val)
|
---|
269 |
|
---|
270 | \overload
|
---|
271 |
|
---|
272 | Sets the value for the field named \a name to \a val.
|
---|
273 | */
|
---|
274 |
|
---|
275 | /*!
|
---|
276 | Constructs a cursor on database \a db using table or view \a name.
|
---|
277 |
|
---|
278 | If \a autopopulate is true (the default), the \a name of the
|
---|
279 | cursor must correspond to an existing table or view name in the
|
---|
280 | database so that field information can be automatically created.
|
---|
281 | If the table or view does not exist, the cursor will not be
|
---|
282 | functional.
|
---|
283 |
|
---|
284 | The cursor is created with an initial mode of Q3SqlCursor::Writable
|
---|
285 | (meaning that records can be inserted, updated or deleted using
|
---|
286 | the cursor). If the cursor does not have a unique primary index,
|
---|
287 | update and deletes cannot be performed.
|
---|
288 |
|
---|
289 | Note that \a autopopulate refers to populating the cursor with
|
---|
290 | meta-data, e.g. the names of the table's fields, not with
|
---|
291 | retrieving data. The select() function is used to populate the
|
---|
292 | cursor with data.
|
---|
293 |
|
---|
294 | \sa setName() setMode()
|
---|
295 | */
|
---|
296 |
|
---|
297 | Q3SqlCursor::Q3SqlCursor(const QString & name, bool autopopulate, QSqlDatabase db)
|
---|
298 | : QSqlRecord(), QSqlQuery(QString(), db)
|
---|
299 | {
|
---|
300 | d = new Q3SqlCursorPrivate(name, db);
|
---|
301 | setMode(Writable);
|
---|
302 | if (!d->nm.isEmpty())
|
---|
303 | setName(d->nm, autopopulate);
|
---|
304 | }
|
---|
305 |
|
---|
306 | /*!
|
---|
307 | Constructs a copy of \a other.
|
---|
308 | */
|
---|
309 |
|
---|
310 | Q3SqlCursor::Q3SqlCursor(const Q3SqlCursor & other)
|
---|
311 | : QSqlRecord(other), QSqlQuery(other)
|
---|
312 | {
|
---|
313 | d = new Q3SqlCursorPrivate(other.d->nm, other.d->db);
|
---|
314 | d->lastAt = other.d->lastAt;
|
---|
315 | d->nm = other.d->nm;
|
---|
316 | d->srt = other.d->srt;
|
---|
317 | d->ftr = other.d->ftr;
|
---|
318 | d->priIndx = other.d->priIndx;
|
---|
319 | d->editBuffer = other.d->editBuffer;
|
---|
320 | d->infoBuffer = other.d->infoBuffer;
|
---|
321 | d->q = 0; // do not share queries
|
---|
322 | setMode(other.mode());
|
---|
323 | }
|
---|
324 |
|
---|
325 | /*!
|
---|
326 | Destroys the object and frees any allocated resources.
|
---|
327 | */
|
---|
328 |
|
---|
329 | Q3SqlCursor::~Q3SqlCursor()
|
---|
330 | {
|
---|
331 | delete d;
|
---|
332 | }
|
---|
333 |
|
---|
334 | /*!
|
---|
335 | Sets the cursor equal to \a other.
|
---|
336 | */
|
---|
337 |
|
---|
338 | Q3SqlCursor& Q3SqlCursor::operator=(const Q3SqlCursor& other)
|
---|
339 | {
|
---|
340 | QSqlRecord::operator=(other);
|
---|
341 | QSqlQuery::operator=(other);
|
---|
342 | delete d;
|
---|
343 | d = new Q3SqlCursorPrivate(other.d->nm, other.d->db);
|
---|
344 | d->lastAt = other.d->lastAt;
|
---|
345 | d->nm = other.d->nm;
|
---|
346 | d->srt = other.d->srt;
|
---|
347 | d->ftr = other.d->ftr;
|
---|
348 | d->priIndx = other.d->priIndx;
|
---|
349 | d->editBuffer = other.d->editBuffer;
|
---|
350 | d->infoBuffer = other.d->infoBuffer;
|
---|
351 | d->q = 0; // do not share queries
|
---|
352 | setMode(other.mode());
|
---|
353 | return *this;
|
---|
354 | }
|
---|
355 |
|
---|
356 | /*!
|
---|
357 | Sets the current sort to \a sort. Note that no new records are
|
---|
358 | selected. To select new records, use select(). The \a sort will
|
---|
359 | apply to any subsequent select() calls that do not explicitly
|
---|
360 | specify a sort.
|
---|
361 | */
|
---|
362 |
|
---|
363 | void Q3SqlCursor::setSort(const QSqlIndex& sort)
|
---|
364 | {
|
---|
365 | d->srt = sort;
|
---|
366 | }
|
---|
367 |
|
---|
368 | /*!
|
---|
369 | Returns the current sort, or an empty index if there is no current
|
---|
370 | sort.
|
---|
371 | */
|
---|
372 | QSqlIndex Q3SqlCursor::sort() const
|
---|
373 | {
|
---|
374 | return d->srt;
|
---|
375 | }
|
---|
376 |
|
---|
377 | /*!
|
---|
378 | Sets the current filter to \a filter. Note that no new records are
|
---|
379 | selected. To select new records, use select(). The \a filter will
|
---|
380 | apply to any subsequent select() calls that do not explicitly
|
---|
381 | specify a filter.
|
---|
382 |
|
---|
383 | The filter is a SQL \c WHERE clause without the keyword 'WHERE',
|
---|
384 | e.g. \c{name='Dave'} which will be processed by the DBMS.
|
---|
385 | */
|
---|
386 | void Q3SqlCursor::setFilter(const QString& filter)
|
---|
387 | {
|
---|
388 | d->ftr = filter;
|
---|
389 | }
|
---|
390 |
|
---|
391 | /*!
|
---|
392 | Returns the current filter, or an empty string if there is no
|
---|
393 | current filter.
|
---|
394 | */
|
---|
395 | QString Q3SqlCursor::filter() const
|
---|
396 | {
|
---|
397 | return d->ftr;
|
---|
398 | }
|
---|
399 |
|
---|
400 | /*!
|
---|
401 | Sets the name of the cursor to \a name. If \a autopopulate is true
|
---|
402 | (the default), the \a name must correspond to a valid table or
|
---|
403 | view name in the database. Also, note that all references to the
|
---|
404 | cursor edit buffer become invalidated when fields are
|
---|
405 | auto-populated. See the Q3SqlCursor constructor documentation for
|
---|
406 | more information.
|
---|
407 | */
|
---|
408 | void Q3SqlCursor::setName(const QString& name, bool autopopulate)
|
---|
409 | {
|
---|
410 | d->nm = name;
|
---|
411 | if (autopopulate) {
|
---|
412 | if (driver()) {
|
---|
413 | d->infoBuffer = driver()->record(name);
|
---|
414 | *this = d->infoBuffer.toRecord();
|
---|
415 | d->editBuffer = *this;
|
---|
416 | d->priIndx = driver()->primaryIndex(name);
|
---|
417 | }
|
---|
418 | if (isEmpty())
|
---|
419 | qWarning("Q3SqlCursor::setName: unable to build record, does '%s' exist?", name.latin1());
|
---|
420 | }
|
---|
421 | }
|
---|
422 |
|
---|
423 | /*!
|
---|
424 | Returns the name of the cursor.
|
---|
425 | */
|
---|
426 |
|
---|
427 | QString Q3SqlCursor::name() const
|
---|
428 | {
|
---|
429 | return d->nm;
|
---|
430 | }
|
---|
431 |
|
---|
432 | /*! \internal
|
---|
433 | */
|
---|
434 |
|
---|
435 | QString Q3SqlCursor::toString(const QString& prefix, const QString& sep) const
|
---|
436 | {
|
---|
437 | QString pflist;
|
---|
438 | QString pfix = prefix.isEmpty() ? prefix : prefix + QLatin1Char('.');
|
---|
439 | bool comma = false;
|
---|
440 |
|
---|
441 | for (int i = 0; i < count(); ++i) {
|
---|
442 | const QString fname = fieldName(i);
|
---|
443 | if (isGenerated(i)) {
|
---|
444 | if(comma)
|
---|
445 | pflist += sep + QLatin1Char(' ');
|
---|
446 | pflist += pfix + driver()->escapeIdentifier(fname, QSqlDriver::FieldName);
|
---|
447 | comma = true;
|
---|
448 | }
|
---|
449 | }
|
---|
450 | return pflist;
|
---|
451 | }
|
---|
452 |
|
---|
453 | /*!
|
---|
454 | \internal
|
---|
455 |
|
---|
456 | Assigns the record \a list.
|
---|
457 |
|
---|
458 | */
|
---|
459 | QSqlRecord & Q3SqlCursor::operator=(const QSqlRecord & list)
|
---|
460 | {
|
---|
461 | return QSqlRecord::operator=(list);
|
---|
462 | }
|
---|
463 |
|
---|
464 | /*!
|
---|
465 | Append a copy of field \a fieldInfo to the end of the cursor. Note
|
---|
466 | that all references to the cursor edit buffer become invalidated.
|
---|
467 | */
|
---|
468 |
|
---|
469 | void Q3SqlCursor::append(const Q3SqlFieldInfo& fieldInfo)
|
---|
470 | {
|
---|
471 | d->editBuffer.append(fieldInfo.toField());
|
---|
472 | d->infoBuffer.append(fieldInfo);
|
---|
473 | QSqlRecord::append(fieldInfo.toField());
|
---|
474 | }
|
---|
475 |
|
---|
476 | /*!
|
---|
477 | Removes all fields from the cursor. Note that all references to
|
---|
478 | the cursor edit buffer become invalidated.
|
---|
479 | */
|
---|
480 | void Q3SqlCursor::clear()
|
---|
481 | {
|
---|
482 | d->editBuffer.clear();
|
---|
483 | d->infoBuffer.clear();
|
---|
484 | QSqlRecord::clear();
|
---|
485 | }
|
---|
486 |
|
---|
487 |
|
---|
488 | /*!
|
---|
489 | Insert a copy of \a fieldInfo at position \a pos. If a field
|
---|
490 | already exists at \a pos, it is removed. Note that all references
|
---|
491 | to the cursor edit buffer become invalidated.
|
---|
492 | */
|
---|
493 |
|
---|
494 | void Q3SqlCursor::insert(int pos, const Q3SqlFieldInfo& fieldInfo)
|
---|
495 | {
|
---|
496 | d->editBuffer.replace(pos, fieldInfo.toField());
|
---|
497 | d->infoBuffer[pos] = fieldInfo;
|
---|
498 | QSqlRecord::replace(pos, fieldInfo.toField());
|
---|
499 | }
|
---|
500 |
|
---|
501 | /*!
|
---|
502 | Removes the field at \a pos. If \a pos does not exist, nothing
|
---|
503 | happens. Note that all references to the cursor edit buffer become
|
---|
504 | invalidated.
|
---|
505 | */
|
---|
506 |
|
---|
507 | void Q3SqlCursor::remove(int pos)
|
---|
508 | {
|
---|
509 | d->editBuffer.remove(pos);
|
---|
510 | d->infoBuffer[pos] = Q3SqlFieldInfo();
|
---|
511 | QSqlRecord::remove(pos);
|
---|
512 | }
|
---|
513 |
|
---|
514 | /*!
|
---|
515 | Sets the generated flag for the field \a name to \a generated. If
|
---|
516 | the field does not exist, nothing happens. Only fields that have
|
---|
517 | \a generated set to true are included in the SQL that is
|
---|
518 | generated by insert(), update() or del().
|
---|
519 | */
|
---|
520 |
|
---|
521 | void Q3SqlCursor::setGenerated(const QString& name, bool generated)
|
---|
522 | {
|
---|
523 | int pos = indexOf(name);
|
---|
524 | if (pos == -1)
|
---|
525 | return;
|
---|
526 | QSqlRecord::setGenerated(name, generated);
|
---|
527 | d->editBuffer.setGenerated(name, generated);
|
---|
528 | d->infoBuffer[pos].setGenerated(generated);
|
---|
529 | }
|
---|
530 |
|
---|
531 | /*!
|
---|
532 | \overload
|
---|
533 |
|
---|
534 | Sets the generated flag for the field \a i to \a generated.
|
---|
535 | */
|
---|
536 | void Q3SqlCursor::setGenerated(int i, bool generated)
|
---|
537 | {
|
---|
538 | if (i < 0 || i >= (int)d->infoBuffer.count())
|
---|
539 | return;
|
---|
540 | QSqlRecord::setGenerated(i, generated);
|
---|
541 | d->editBuffer.setGenerated(i, generated);
|
---|
542 | d->infoBuffer[i].setGenerated(generated);
|
---|
543 | }
|
---|
544 |
|
---|
545 | /*!
|
---|
546 | Returns the primary index associated with the cursor as defined in
|
---|
547 | the database, or an empty index if there is no primary index. If
|
---|
548 | \a setFromCursor is true (the default), the index fields are
|
---|
549 | populated with the corresponding values in the cursor's current
|
---|
550 | record.
|
---|
551 | */
|
---|
552 |
|
---|
553 | QSqlIndex Q3SqlCursor::primaryIndex(bool setFromCursor) const
|
---|
554 | {
|
---|
555 | if (setFromCursor) {
|
---|
556 | for (int i = 0; i < d->priIndx.count(); ++i) {
|
---|
557 | const QString fn = d->priIndx.fieldName(i);
|
---|
558 | if (contains(fn))
|
---|
559 | d->priIndx.setValue(i, QSqlRecord::value(fn));
|
---|
560 | }
|
---|
561 | }
|
---|
562 | return d->priIndx;
|
---|
563 | }
|
---|
564 |
|
---|
565 | /*!
|
---|
566 | Sets the primary index associated with the cursor to the index \a
|
---|
567 | idx. Note that this index must contain a field or set of fields
|
---|
568 | which identify a unique record within the underlying database
|
---|
569 | table or view so that update() and del() will execute as expected.
|
---|
570 |
|
---|
571 | \sa update() del()
|
---|
572 | */
|
---|
573 |
|
---|
574 | void Q3SqlCursor::setPrimaryIndex(const QSqlIndex& idx)
|
---|
575 | {
|
---|
576 | d->priIndx = idx;
|
---|
577 | }
|
---|
578 |
|
---|
579 |
|
---|
580 | /*!
|
---|
581 | Returns an index composed of \a fieldNames, all in ASCending
|
---|
582 | order. Note that all field names must exist in the cursor,
|
---|
583 | otherwise an empty index is returned.
|
---|
584 |
|
---|
585 | \sa QSqlIndex
|
---|
586 | */
|
---|
587 |
|
---|
588 | QSqlIndex Q3SqlCursor::index(const QStringList& fieldNames) const
|
---|
589 | {
|
---|
590 | QSqlIndex idx;
|
---|
591 | for (QStringList::ConstIterator it = fieldNames.begin(); it != fieldNames.end(); ++it) {
|
---|
592 | QSqlField f = field((*it));
|
---|
593 | if (!f.isValid()) { /* all fields must exist */
|
---|
594 | idx.clear();
|
---|
595 | break;
|
---|
596 | }
|
---|
597 | idx.append(f);
|
---|
598 | }
|
---|
599 | return idx;
|
---|
600 | }
|
---|
601 |
|
---|
602 | /*!
|
---|
603 | \overload
|
---|
604 |
|
---|
605 | Returns an index based on \a fieldName.
|
---|
606 | */
|
---|
607 |
|
---|
608 | QSqlIndex Q3SqlCursor::index(const QString& fieldName) const
|
---|
609 | {
|
---|
610 | QStringList fl(fieldName);
|
---|
611 | return index(fl);
|
---|
612 | }
|
---|
613 |
|
---|
614 | /*!
|
---|
615 | Selects all fields in the cursor from the database matching the
|
---|
616 | filter criteria \a filter. The data is returned in the order
|
---|
617 | specified by the index \a sort. Returns true if the data was
|
---|
618 | successfully selected; otherwise returns false.
|
---|
619 |
|
---|
620 | The \a filter is a string containing a SQL \c WHERE clause but
|
---|
621 | without the 'WHERE' keyword. The cursor is initially positioned at
|
---|
622 | an invalid row after this function is called. To move to a valid
|
---|
623 | row, use seek(), first(), last(), previous() or next().
|
---|
624 |
|
---|
625 | Example:
|
---|
626 | \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 2
|
---|
627 |
|
---|
628 | The filter will apply to any subsequent select() calls that do not
|
---|
629 | explicitly specify another filter. Similarly the sort will apply
|
---|
630 | to any subsequent select() calls that do not explicitly specify
|
---|
631 | another sort.
|
---|
632 |
|
---|
633 | \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 3
|
---|
634 |
|
---|
635 | */
|
---|
636 |
|
---|
637 | bool Q3SqlCursor::select(const QString & filter, const QSqlIndex & sort)
|
---|
638 | {
|
---|
639 | QString fieldList(toString(d->nm));
|
---|
640 | if (fieldList.isEmpty())
|
---|
641 | return false;
|
---|
642 | QString str(QLatin1String("select ") + fieldList);
|
---|
643 | str += QLatin1String(" from ") + d->nm;
|
---|
644 | if (!filter.isEmpty()) {
|
---|
645 | d->ftr = filter;
|
---|
646 | str += QLatin1String(" where ") + filter;
|
---|
647 | } else
|
---|
648 | d->ftr.clear();
|
---|
649 | if (sort.count() > 0)
|
---|
650 | str += QLatin1String(" order by ") + sort.toString(d->nm);
|
---|
651 | d->srt = sort;
|
---|
652 | return exec(str);
|
---|
653 | }
|
---|
654 |
|
---|
655 | /*!
|
---|
656 | \overload
|
---|
657 |
|
---|
658 | Selects all fields in the cursor from the database. The rows are
|
---|
659 | returned in the order specified by the last call to setSort() or
|
---|
660 | the last call to select() that specified a sort, whichever is the
|
---|
661 | most recent. If there is no current sort, the order in which the
|
---|
662 | rows are returned is undefined. The records are filtered according
|
---|
663 | to the filter specified by the last call to setFilter() or the
|
---|
664 | last call to select() that specified a filter, whichever is the
|
---|
665 | most recent. If there is no current filter, all records are
|
---|
666 | returned. The cursor is initially positioned at an invalid row. To
|
---|
667 | move to a valid row, use seek(), first(), last(), previous() or
|
---|
668 | next().
|
---|
669 |
|
---|
670 | \sa setSort() setFilter()
|
---|
671 | */
|
---|
672 |
|
---|
673 | bool Q3SqlCursor::select()
|
---|
674 | {
|
---|
675 | return select(filter(), sort());
|
---|
676 | }
|
---|
677 |
|
---|
678 | /*!
|
---|
679 | \overload
|
---|
680 |
|
---|
681 | Selects all fields in the cursor from the database. The data is
|
---|
682 | returned in the order specified by the index \a sort. The records
|
---|
683 | are filtered according to the filter specified by the last call to
|
---|
684 | setFilter() or the last call to select() that specified a filter,
|
---|
685 | whichever is the most recent. The cursor is initially positioned
|
---|
686 | at an invalid row. To move to a valid row, use seek(), first(),
|
---|
687 | last(), previous() or next().
|
---|
688 | */
|
---|
689 |
|
---|
690 | bool Q3SqlCursor::select(const QSqlIndex& sort)
|
---|
691 | {
|
---|
692 | return select(filter(), sort);
|
---|
693 | }
|
---|
694 |
|
---|
695 | /*!
|
---|
696 | \overload
|
---|
697 |
|
---|
698 | Selects all fields in the cursor matching the filter index \a
|
---|
699 | filter. The data is returned in the order specified by the index
|
---|
700 | \a sort. The \a filter index works by constructing a WHERE clause
|
---|
701 | using the names of the fields from the \a filter and their values
|
---|
702 | from the current cursor record. The cursor is initially positioned
|
---|
703 | at an invalid row. To move to a valid row, use seek(), first(),
|
---|
704 | last(), previous() or next(). This function is useful, for example,
|
---|
705 | for retrieving data based upon a table's primary index:
|
---|
706 |
|
---|
707 | \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 4
|
---|
708 |
|
---|
709 | In this example the QSqlIndex, pk, is used for two different
|
---|
710 | purposes. When used as the filter (first) argument, the field
|
---|
711 | names it contains are used to construct the WHERE clause, each set
|
---|
712 | to the current cursor value, \c{WHERE id=10}, in this case. When
|
---|
713 | used as the sort (second) argument the field names it contains are
|
---|
714 | used for the ORDER BY clause, \c{ORDER BY id} in this example.
|
---|
715 | */
|
---|
716 |
|
---|
717 | bool Q3SqlCursor::select(const QSqlIndex & filter, const QSqlIndex & sort)
|
---|
718 | {
|
---|
719 | return select(toString(filter, this, d->nm, QString(QLatin1Char('=')), QLatin1String("and")), sort);
|
---|
720 | }
|
---|
721 |
|
---|
722 | /*!
|
---|
723 | Sets the cursor mode to \a mode. This value can be an OR'ed
|
---|
724 | combination of \l Q3SqlCursor::Mode values. The default mode for a
|
---|
725 | cursor is Q3SqlCursor::Writable.
|
---|
726 |
|
---|
727 | \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 5
|
---|
728 | */
|
---|
729 |
|
---|
730 | void Q3SqlCursor::setMode(int mode)
|
---|
731 | {
|
---|
732 | d->md = mode;
|
---|
733 | }
|
---|
734 |
|
---|
735 | /*!
|
---|
736 | Returns the current cursor mode.
|
---|
737 |
|
---|
738 | \sa setMode()
|
---|
739 | */
|
---|
740 |
|
---|
741 | int Q3SqlCursor::mode() const
|
---|
742 | {
|
---|
743 | return d->md;
|
---|
744 | }
|
---|
745 |
|
---|
746 | /*!
|
---|
747 | Sets field \a name to \a calculated. If the field \a name does not
|
---|
748 | exist, nothing happens. The value of a calculated field is set by
|
---|
749 | the calculateField() virtual function which you must reimplement
|
---|
750 | (or the field value will be an invalid QVariant). Calculated
|
---|
751 | fields do not appear in generated SQL statements sent to the
|
---|
752 | database.
|
---|
753 |
|
---|
754 | \sa calculateField()
|
---|
755 | */
|
---|
756 |
|
---|
757 | void Q3SqlCursor::setCalculated(const QString& name, bool calculated)
|
---|
758 | {
|
---|
759 | int pos = indexOf(name);
|
---|
760 | if (pos < 0)
|
---|
761 | return;
|
---|
762 | d->infoBuffer[pos].setCalculated(calculated);
|
---|
763 | if (calculated)
|
---|
764 | setGenerated(pos, false);
|
---|
765 | }
|
---|
766 |
|
---|
767 | /*!
|
---|
768 | Returns true if the field \a name exists and is calculated;
|
---|
769 | otherwise returns false.
|
---|
770 |
|
---|
771 | \sa setCalculated()
|
---|
772 | */
|
---|
773 |
|
---|
774 | bool Q3SqlCursor::isCalculated(const QString& name) const
|
---|
775 | {
|
---|
776 | int pos = indexOf(name);
|
---|
777 | if (pos < 0)
|
---|
778 | return false;
|
---|
779 | return d->infoBuffer[pos].isCalculated();
|
---|
780 | }
|
---|
781 |
|
---|
782 | /*!
|
---|
783 | Sets field \a{name}'s trimmed status to \a trim. If the field \a
|
---|
784 | name does not exist, nothing happens.
|
---|
785 |
|
---|
786 | When a trimmed field of type string is read from the
|
---|
787 | database any trailing (right-most) spaces are removed.
|
---|
788 |
|
---|
789 | \sa isTrimmed() QVariant
|
---|
790 | */
|
---|
791 |
|
---|
792 | void Q3SqlCursor::setTrimmed(const QString& name, bool trim)
|
---|
793 | {
|
---|
794 | int pos = indexOf(name);
|
---|
795 | if (pos < 0)
|
---|
796 | return;
|
---|
797 | d->infoBuffer[pos].setTrim(trim);
|
---|
798 | }
|
---|
799 |
|
---|
800 | /*!
|
---|
801 | Returns true if the field \a name exists and is trimmed; otherwise
|
---|
802 | returns false.
|
---|
803 |
|
---|
804 | When a trimmed field of type string or cstring is read from the
|
---|
805 | database any trailing (right-most) spaces are removed.
|
---|
806 |
|
---|
807 | \sa setTrimmed()
|
---|
808 | */
|
---|
809 |
|
---|
810 | bool Q3SqlCursor::isTrimmed(const QString& name) const
|
---|
811 | {
|
---|
812 | int pos = indexOf(name);
|
---|
813 | if (pos < 0)
|
---|
814 | return false;
|
---|
815 | return d->infoBuffer[pos].isTrim();
|
---|
816 | }
|
---|
817 |
|
---|
818 | /*!
|
---|
819 | Returns true if the cursor is read-only; otherwise returns false.
|
---|
820 | The default is false. Read-only cursors cannot be edited using
|
---|
821 | insert(), update() or del().
|
---|
822 |
|
---|
823 | \sa setMode()
|
---|
824 | */
|
---|
825 |
|
---|
826 | bool Q3SqlCursor::isReadOnly() const
|
---|
827 | {
|
---|
828 | return d->md == 0;
|
---|
829 | }
|
---|
830 |
|
---|
831 | /*!
|
---|
832 | Returns true if the cursor will perform inserts; otherwise returns
|
---|
833 | false.
|
---|
834 |
|
---|
835 | \sa setMode()
|
---|
836 | */
|
---|
837 |
|
---|
838 | bool Q3SqlCursor::canInsert() const
|
---|
839 | {
|
---|
840 | return ((d->md & Insert) == Insert) ;
|
---|
841 | }
|
---|
842 |
|
---|
843 |
|
---|
844 | /*!
|
---|
845 | Returns true if the cursor will perform updates; otherwise returns
|
---|
846 | false.
|
---|
847 |
|
---|
848 | \sa setMode()
|
---|
849 | */
|
---|
850 |
|
---|
851 | bool Q3SqlCursor::canUpdate() const
|
---|
852 | {
|
---|
853 | return ((d->md & Update) == Update) ;
|
---|
854 | }
|
---|
855 |
|
---|
856 | /*!
|
---|
857 | Returns true if the cursor will perform deletes; otherwise returns
|
---|
858 | false.
|
---|
859 |
|
---|
860 | \sa setMode()
|
---|
861 | */
|
---|
862 |
|
---|
863 | bool Q3SqlCursor::canDelete() const
|
---|
864 | {
|
---|
865 | return ((d->md & Delete) == Delete) ;
|
---|
866 | }
|
---|
867 |
|
---|
868 | /*!
|
---|
869 | \overload
|
---|
870 |
|
---|
871 | Returns a formatted string composed of the \a prefix (e.g. table
|
---|
872 | or view name), ".", the \a field name, the \a fieldSep and the
|
---|
873 | field value. If the \a prefix is empty then the string will begin
|
---|
874 | with the \a field name. This function is useful for generating SQL
|
---|
875 | statements.
|
---|
876 | */
|
---|
877 |
|
---|
878 | QString Q3SqlCursor::toString(const QString& prefix, QSqlField* field, const QString& fieldSep) const
|
---|
879 | {
|
---|
880 | QString f;
|
---|
881 | if (field && driver()) {
|
---|
882 | f = (prefix.length() > 0 ? prefix + QLatin1Char('.') : QString()) + driver()->escapeIdentifier(field->name(), QSqlDriver::FieldName);
|
---|
883 | f += QLatin1Char(' ') + fieldSep + QLatin1Char(' ');
|
---|
884 | if (field->isNull()) {
|
---|
885 | f += QLatin1String("NULL");
|
---|
886 | } else {
|
---|
887 | f += driver()->formatValue(field);
|
---|
888 | }
|
---|
889 | }
|
---|
890 | return f;
|
---|
891 | }
|
---|
892 |
|
---|
893 | /*!
|
---|
894 | Returns a formatted string composed of all the fields in \a rec.
|
---|
895 | Each field is composed of the \a prefix (e.g. table or view name),
|
---|
896 | ".", the field name, the \a fieldSep and the field value. If the
|
---|
897 | \a prefix is empty then each field will begin with the field name.
|
---|
898 | The fields are then joined together separated by \a sep. Fields
|
---|
899 | where isGenerated() returns false are not included. This function
|
---|
900 | is useful for generating SQL statements.
|
---|
901 | */
|
---|
902 |
|
---|
903 | QString Q3SqlCursor::toString(QSqlRecord* rec, const QString& prefix, const QString& fieldSep,
|
---|
904 | const QString& sep) const
|
---|
905 | {
|
---|
906 | static QString blank(QLatin1Char(' '));
|
---|
907 | QString filter;
|
---|
908 | bool separator = false;
|
---|
909 | for (int j = 0; j < count(); ++j) {
|
---|
910 | QSqlField f = rec->field(j);
|
---|
911 | if (rec->isGenerated(j)) {
|
---|
912 | if (separator)
|
---|
913 | filter += sep + blank;
|
---|
914 | filter += toString(prefix, &f, fieldSep);
|
---|
915 | filter += blank;
|
---|
916 | separator = true;
|
---|
917 | }
|
---|
918 | }
|
---|
919 | return filter;
|
---|
920 | }
|
---|
921 |
|
---|
922 | /*!
|
---|
923 | \overload
|
---|
924 |
|
---|
925 | Returns a formatted string composed of all the fields in the index
|
---|
926 | \a i. Each field is composed of the \a prefix (e.g. table or view
|
---|
927 | name), ".", the field name, the \a fieldSep and the field value.
|
---|
928 | If the \a prefix is empty then each field will begin with the field
|
---|
929 | name. The field values are taken from \a rec. The fields are then
|
---|
930 | joined together separated by \a sep. Fields where isGenerated()
|
---|
931 | returns false are ignored. This function is useful for generating
|
---|
932 | SQL statements.
|
---|
933 | */
|
---|
934 |
|
---|
935 | QString Q3SqlCursor::toString(const QSqlIndex& i, QSqlRecord* rec, const QString& prefix,
|
---|
936 | const QString& fieldSep, const QString& sep) const
|
---|
937 | {
|
---|
938 | QString filter;
|
---|
939 | bool separator = false;
|
---|
940 | for(int j = 0; j < i.count(); ++j){
|
---|
941 | if (rec->isGenerated(j)) {
|
---|
942 | if(separator) {
|
---|
943 | filter += QLatin1Char(' ') + sep + QLatin1Char(' ') ;
|
---|
944 | }
|
---|
945 | QString fn = i.fieldName(j);
|
---|
946 | QSqlField f = rec->field(fn);
|
---|
947 | filter += toString(prefix, &f, fieldSep);
|
---|
948 | separator = true;
|
---|
949 | }
|
---|
950 | }
|
---|
951 | return filter;
|
---|
952 | }
|
---|
953 |
|
---|
954 | /*!
|
---|
955 | Inserts the current contents of the cursor's edit record buffer
|
---|
956 | into the database, if the cursor allows inserts. Returns the
|
---|
957 | number of rows affected by the insert. For error information, use
|
---|
958 | lastError().
|
---|
959 |
|
---|
960 | If \a invalidate is true (the default), the cursor will no longer
|
---|
961 | be positioned on a valid record and can no longer be navigated. A
|
---|
962 | new select() call must be made before navigating to a valid
|
---|
963 | record.
|
---|
964 |
|
---|
965 | \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 6
|
---|
966 |
|
---|
967 | In the above example, a cursor is created on the 'prices' table
|
---|
968 | and a pointer to the insert buffer is acquired using primeInsert().
|
---|
969 | Each field's value is set to the desired value and then insert()
|
---|
970 | is called to insert the data into the database. Remember: all edit
|
---|
971 | operations (insert(), update() and delete()) operate on the
|
---|
972 | contents of the cursor edit buffer and not on the contents of the
|
---|
973 | cursor itself.
|
---|
974 |
|
---|
975 | \sa setMode() lastError()
|
---|
976 | */
|
---|
977 |
|
---|
978 | int Q3SqlCursor::insert(bool invalidate)
|
---|
979 | {
|
---|
980 | if ((d->md & Insert) != Insert || !driver())
|
---|
981 | return false;
|
---|
982 | int k = d->editBuffer.count();
|
---|
983 | if (k == 0)
|
---|
984 | return 0;
|
---|
985 |
|
---|
986 | QString fList;
|
---|
987 | QString vList;
|
---|
988 | bool comma = false;
|
---|
989 | // use a prepared query if the driver supports it
|
---|
990 | if (driver()->hasFeature(QSqlDriver::PreparedQueries)) {
|
---|
991 | int cnt = 0;
|
---|
992 | bool oraStyle = driver()->hasFeature(QSqlDriver::NamedPlaceholders);
|
---|
993 | for(int j = 0; j < k; ++j) {
|
---|
994 | QSqlField f = d->editBuffer.field(j);
|
---|
995 | if (d->editBuffer.isGenerated(j)) {
|
---|
996 | if (comma) {
|
---|
997 | fList += QLatin1Char(',');
|
---|
998 | vList += QLatin1Char(',');
|
---|
999 | }
|
---|
1000 | fList += driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName);
|
---|
1001 | vList += (oraStyle == true) ? QLatin1String(":f") + QString::number(cnt) : QString(QLatin1Char('?'));
|
---|
1002 | cnt++;
|
---|
1003 | comma = true;
|
---|
1004 | }
|
---|
1005 | }
|
---|
1006 | if (!comma) {
|
---|
1007 | return 0;
|
---|
1008 | }
|
---|
1009 | QString str;
|
---|
1010 | str.append(QLatin1String("insert into ")).append(name())
|
---|
1011 | .append(QLatin1String(" (")).append(fList)
|
---|
1012 | .append(QLatin1String(") values (")).append(vList). append(QLatin1Char(')'));
|
---|
1013 |
|
---|
1014 | return applyPrepared(str, invalidate);
|
---|
1015 | } else {
|
---|
1016 | for(int j = 0; j < k; ++j) {
|
---|
1017 | QSqlField f = d->editBuffer.field(j);
|
---|
1018 | if (d->editBuffer.isGenerated(j)) {
|
---|
1019 | if (comma) {
|
---|
1020 | fList += QLatin1Char(',');
|
---|
1021 | vList += QLatin1Char(',');
|
---|
1022 | }
|
---|
1023 | fList += driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName);
|
---|
1024 | vList += driver()->formatValue(&f);
|
---|
1025 | comma = true;
|
---|
1026 | }
|
---|
1027 | }
|
---|
1028 |
|
---|
1029 | if (!comma) {
|
---|
1030 | // no valid fields found
|
---|
1031 | return 0;
|
---|
1032 | }
|
---|
1033 | QString str;
|
---|
1034 | str.append(QLatin1String("insert into ")).append(name()).append(QLatin1String(" ("))
|
---|
1035 | .append(fList).append(QLatin1String(") values (")).append(vList). append (QLatin1String(")"));
|
---|
1036 | return apply(str, invalidate);
|
---|
1037 | }
|
---|
1038 | }
|
---|
1039 |
|
---|
1040 | /*!
|
---|
1041 | Returns the current internal edit buffer. If \a copy is true (the
|
---|
1042 | default is false), the current cursor field values are first
|
---|
1043 | copied into the edit buffer. The edit buffer is valid as long as
|
---|
1044 | the cursor remains valid. The cursor retains ownership of the
|
---|
1045 | returned pointer, so it must not be deleted or modified.
|
---|
1046 |
|
---|
1047 | \sa primeInsert(), primeUpdate() primeDelete()
|
---|
1048 | */
|
---|
1049 |
|
---|
1050 | QSqlRecord* Q3SqlCursor::editBuffer(bool copy)
|
---|
1051 | {
|
---|
1052 | sync();
|
---|
1053 | if (copy) {
|
---|
1054 | for(int i = 0; i < d->editBuffer.count(); i++) {
|
---|
1055 | if (QSqlRecord::isNull(i)) {
|
---|
1056 | d->editBuffer.setNull(i);
|
---|
1057 | } else {
|
---|
1058 | d->editBuffer.setValue(i, value(i));
|
---|
1059 | }
|
---|
1060 | }
|
---|
1061 | }
|
---|
1062 | return &d->editBuffer;
|
---|
1063 | }
|
---|
1064 |
|
---|
1065 | /*!
|
---|
1066 | This function primes the edit buffer's field values for update and
|
---|
1067 | returns the edit buffer. The default implementation copies the
|
---|
1068 | field values from the current cursor record into the edit buffer
|
---|
1069 | (therefore, this function is equivalent to calling editBuffer(
|
---|
1070 | true)). The cursor retains ownership of the returned pointer, so
|
---|
1071 | it must not be deleted or modified.
|
---|
1072 |
|
---|
1073 | \sa editBuffer() update()
|
---|
1074 | */
|
---|
1075 |
|
---|
1076 | QSqlRecord* Q3SqlCursor::primeUpdate()
|
---|
1077 | {
|
---|
1078 | // memorize the primary keys as they were before the user changed the values in editBuffer
|
---|
1079 | QSqlRecord* buf = editBuffer(true);
|
---|
1080 | QSqlIndex idx = primaryIndex(false);
|
---|
1081 | if (!idx.isEmpty())
|
---|
1082 | d->editIndex = toString(idx, buf, d->nm, QString(QLatin1Char('=')), QLatin1String("and"));
|
---|
1083 | else
|
---|
1084 | d->editIndex = qWhereClause(buf, d->nm, QLatin1String("and"), driver());
|
---|
1085 | return buf;
|
---|
1086 | }
|
---|
1087 |
|
---|
1088 | /*!
|
---|
1089 | This function primes the edit buffer's field values for delete and
|
---|
1090 | returns the edit buffer. The default implementation copies the
|
---|
1091 | field values from the current cursor record into the edit buffer
|
---|
1092 | (therefore, this function is equivalent to calling editBuffer(
|
---|
1093 | true)). The cursor retains ownership of the returned pointer, so
|
---|
1094 | it must not be deleted or modified.
|
---|
1095 |
|
---|
1096 | \sa editBuffer() del()
|
---|
1097 | */
|
---|
1098 |
|
---|
1099 | QSqlRecord* Q3SqlCursor::primeDelete()
|
---|
1100 | {
|
---|
1101 | return editBuffer(true);
|
---|
1102 | }
|
---|
1103 |
|
---|
1104 | /*!
|
---|
1105 | This function primes the edit buffer's field values for insert and
|
---|
1106 | returns the edit buffer. The default implementation clears all
|
---|
1107 | field values in the edit buffer. The cursor retains ownership of
|
---|
1108 | the returned pointer, so it must not be deleted or modified.
|
---|
1109 |
|
---|
1110 | \sa editBuffer() insert()
|
---|
1111 | */
|
---|
1112 |
|
---|
1113 | QSqlRecord* Q3SqlCursor::primeInsert()
|
---|
1114 | {
|
---|
1115 | d->editBuffer.clearValues();
|
---|
1116 | return &d->editBuffer;
|
---|
1117 | }
|
---|
1118 |
|
---|
1119 |
|
---|
1120 | /*!
|
---|
1121 | Updates the database with the current contents of the edit buffer.
|
---|
1122 | Returns the number of records which were updated.
|
---|
1123 | For error information, use lastError().
|
---|
1124 |
|
---|
1125 | Only records which meet the filter criteria specified by the
|
---|
1126 | cursor's primary index are updated. If the cursor does not contain
|
---|
1127 | a primary index, no update is performed and 0 is returned.
|
---|
1128 |
|
---|
1129 | If \a invalidate is true (the default), the current cursor can no
|
---|
1130 | longer be navigated. A new select() call must be made before you
|
---|
1131 | can move to a valid record. For example:
|
---|
1132 |
|
---|
1133 | \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 7
|
---|
1134 |
|
---|
1135 | In the above example, a cursor is created on the 'prices' table
|
---|
1136 | and is positioned on the record to be updated. Then a pointer to
|
---|
1137 | the cursor's edit buffer is acquired using primeUpdate(). A new
|
---|
1138 | value is calculated and placed into the edit buffer with the
|
---|
1139 | setValue() call. Finally, an update() call is made on the cursor
|
---|
1140 | which uses the tables's primary index to update the record in the
|
---|
1141 | database with the contents of the cursor's edit buffer. Remember:
|
---|
1142 | all edit operations (insert(), update() and delete()) operate on
|
---|
1143 | the contents of the cursor edit buffer and not on the contents of
|
---|
1144 | the cursor itself.
|
---|
1145 |
|
---|
1146 | Note that if the primary index does not uniquely distinguish
|
---|
1147 | records the database may be changed into an inconsistent state.
|
---|
1148 |
|
---|
1149 | \sa setMode() lastError()
|
---|
1150 | */
|
---|
1151 |
|
---|
1152 | int Q3SqlCursor::update(bool invalidate)
|
---|
1153 | {
|
---|
1154 | if (d->editIndex.isEmpty())
|
---|
1155 | return 0;
|
---|
1156 | return update(d->editIndex, invalidate);
|
---|
1157 | }
|
---|
1158 |
|
---|
1159 | /*!
|
---|
1160 | \overload
|
---|
1161 |
|
---|
1162 | Updates the database with the current contents of the cursor edit
|
---|
1163 | buffer using the specified \a filter. Returns the number of
|
---|
1164 | records which were updated.
|
---|
1165 | For error information, use lastError().
|
---|
1166 |
|
---|
1167 | Only records which meet the filter criteria are updated, otherwise
|
---|
1168 | all records in the table are updated.
|
---|
1169 |
|
---|
1170 | If \a invalidate is true (the default), the cursor can no longer
|
---|
1171 | be navigated. A new select() call must be made before you can move
|
---|
1172 | to a valid record.
|
---|
1173 |
|
---|
1174 | \sa primeUpdate() setMode() lastError()
|
---|
1175 | */
|
---|
1176 |
|
---|
1177 | int Q3SqlCursor::update(const QString & filter, bool invalidate)
|
---|
1178 | {
|
---|
1179 | if ((d->md & Update) != Update) {
|
---|
1180 | return false;
|
---|
1181 | }
|
---|
1182 | int k = count();
|
---|
1183 | if (k == 0) {
|
---|
1184 | return 0;
|
---|
1185 | }
|
---|
1186 |
|
---|
1187 | // use a prepared query if the driver supports it
|
---|
1188 | if (driver()->hasFeature(QSqlDriver::PreparedQueries)) {
|
---|
1189 | QString fList;
|
---|
1190 | bool comma = false;
|
---|
1191 | int cnt = 0;
|
---|
1192 | bool oraStyle = driver()->hasFeature(QSqlDriver::NamedPlaceholders);
|
---|
1193 | for(int j = 0; j < k; ++j) {
|
---|
1194 | QSqlField f = d->editBuffer.field(j);
|
---|
1195 | if (d->editBuffer.isGenerated(j)) {
|
---|
1196 | if (comma) {
|
---|
1197 | fList += QLatin1Char(',');
|
---|
1198 | }
|
---|
1199 | fList += f.name() + QLatin1String(" = ") + (oraStyle == true ? QLatin1String(":f") + QString::number(cnt) : QString(QLatin1Char('?')));
|
---|
1200 | cnt++;
|
---|
1201 | comma = true;
|
---|
1202 | }
|
---|
1203 | }
|
---|
1204 | if (!comma) {
|
---|
1205 | return 0;
|
---|
1206 | }
|
---|
1207 | QString str(QLatin1String("update ") + name() + QLatin1String(" set ") + fList);
|
---|
1208 | if (filter.length()) {
|
---|
1209 | str+= QLatin1String(" where ") + filter;
|
---|
1210 | }
|
---|
1211 | return applyPrepared(str, invalidate);
|
---|
1212 | } else {
|
---|
1213 | QString str = QLatin1String("update ") + name();
|
---|
1214 | str += QLatin1String(" set ") + toString(&d->editBuffer, QString(), QString(QLatin1Char('=')), QString(QLatin1Char(',')));
|
---|
1215 | if (filter.length()) {
|
---|
1216 | str+= QLatin1String(" where ") + filter;
|
---|
1217 | }
|
---|
1218 | return apply(str, invalidate);
|
---|
1219 | }
|
---|
1220 | }
|
---|
1221 |
|
---|
1222 | /*!
|
---|
1223 | Deletes a record from the database using the cursor's primary
|
---|
1224 | index and the contents of the cursor edit buffer. Returns the
|
---|
1225 | number of records which were deleted.
|
---|
1226 | For error information, use lastError().
|
---|
1227 |
|
---|
1228 | Only records which meet the filter criteria specified by the
|
---|
1229 | cursor's primary index are deleted. If the cursor does not contain
|
---|
1230 | a primary index, no delete is performed and 0 is returned. If \a
|
---|
1231 | invalidate is true (the default), the current cursor can no longer
|
---|
1232 | be navigated. A new select() call must be made before you can move
|
---|
1233 | to a valid record. For example:
|
---|
1234 |
|
---|
1235 | \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 8
|
---|
1236 |
|
---|
1237 | In the above example, a cursor is created on the 'prices' table
|
---|
1238 | and positioned to the record to be deleted. First primeDelete() is
|
---|
1239 | called to populate the edit buffer with the current cursor values,
|
---|
1240 | e.g. with an id of 999, and then del() is called to actually
|
---|
1241 | delete the record from the database. Remember: all edit operations
|
---|
1242 | (insert(), update() and delete()) operate on the contents of the
|
---|
1243 | cursor edit buffer and not on the contents of the cursor itself.
|
---|
1244 |
|
---|
1245 | \sa primeDelete() setMode() lastError()
|
---|
1246 | */
|
---|
1247 |
|
---|
1248 | int Q3SqlCursor::del(bool invalidate)
|
---|
1249 | {
|
---|
1250 | QSqlIndex idx = primaryIndex(false);
|
---|
1251 | if (idx.isEmpty())
|
---|
1252 | return del(qWhereClause(&d->editBuffer, d->nm, QLatin1String("and"), driver()), invalidate);
|
---|
1253 | return del(toString(primaryIndex(), &d->editBuffer, d->nm, QString(QLatin1Char('=')), QLatin1String("and")), invalidate);
|
---|
1254 | }
|
---|
1255 |
|
---|
1256 | /*!
|
---|
1257 | \overload
|
---|
1258 |
|
---|
1259 | Deletes the current cursor record from the database using the
|
---|
1260 | filter \a filter. Only records which meet the filter criteria are
|
---|
1261 | deleted. Returns the number of records which were deleted. If \a
|
---|
1262 | invalidate is true (the default), the current cursor can no longer
|
---|
1263 | be navigated. A new select() call must be made before you can move
|
---|
1264 | to a valid record. For error information, use lastError().
|
---|
1265 |
|
---|
1266 | The \a filter is an SQL \c WHERE clause, e.g. \c{id=500}.
|
---|
1267 |
|
---|
1268 | \sa setMode() lastError()
|
---|
1269 | */
|
---|
1270 |
|
---|
1271 | int Q3SqlCursor::del(const QString & filter, bool invalidate)
|
---|
1272 | {
|
---|
1273 | if ((d->md & Delete) != Delete)
|
---|
1274 | return 0;
|
---|
1275 | int k = count();
|
---|
1276 | if(k == 0) return 0;
|
---|
1277 | QString str = QLatin1String("delete from ") + name();
|
---|
1278 | if (filter.length())
|
---|
1279 | str+= QLatin1String(" where ") + filter;
|
---|
1280 | return apply(str, invalidate);
|
---|
1281 | }
|
---|
1282 |
|
---|
1283 | /*
|
---|
1284 | \internal
|
---|
1285 | */
|
---|
1286 |
|
---|
1287 | int Q3SqlCursor::apply(const QString& q, bool invalidate)
|
---|
1288 | {
|
---|
1289 | int ar = 0;
|
---|
1290 | if (invalidate) {
|
---|
1291 | if (exec(q))
|
---|
1292 | ar = numRowsAffected();
|
---|
1293 | } else if (driver()) {
|
---|
1294 | QSqlQuery* sql = d->query();
|
---|
1295 | if (sql && sql->exec(q))
|
---|
1296 | ar = sql->numRowsAffected();
|
---|
1297 | }
|
---|
1298 | return ar;
|
---|
1299 | }
|
---|
1300 |
|
---|
1301 | /*
|
---|
1302 | \internal
|
---|
1303 | */
|
---|
1304 |
|
---|
1305 | int Q3SqlCursor::applyPrepared(const QString& q, bool invalidate)
|
---|
1306 | {
|
---|
1307 | int ar = 0;
|
---|
1308 | QSqlQuery* sql = 0;
|
---|
1309 |
|
---|
1310 | if (invalidate) {
|
---|
1311 | sql = (QSqlQuery*)this;
|
---|
1312 | d->lastAt = QSql::BeforeFirst;
|
---|
1313 | } else {
|
---|
1314 | sql = d->query();
|
---|
1315 | }
|
---|
1316 | if (!sql)
|
---|
1317 | return 0;
|
---|
1318 |
|
---|
1319 | if (invalidate || sql->lastQuery() != q) {
|
---|
1320 | if (!sql->prepare(q))
|
---|
1321 | return 0;
|
---|
1322 | }
|
---|
1323 |
|
---|
1324 | int cnt = 0;
|
---|
1325 | int fieldCount = (int)count();
|
---|
1326 | for (int j = 0; j < fieldCount; ++j) {
|
---|
1327 | const QSqlField f = d->editBuffer.field(j);
|
---|
1328 | if (d->editBuffer.isGenerated(j)) {
|
---|
1329 | if (f.type() == QVariant::ByteArray)
|
---|
1330 | sql->bindValue(cnt, f.value(), QSql::In | QSql::Binary);
|
---|
1331 | else
|
---|
1332 | sql->bindValue(cnt, f.value());
|
---|
1333 | cnt++;
|
---|
1334 | }
|
---|
1335 | }
|
---|
1336 | if (sql->exec()) {
|
---|
1337 | ar = sql->numRowsAffected();
|
---|
1338 | }
|
---|
1339 | return ar;
|
---|
1340 | }
|
---|
1341 |
|
---|
1342 | /*!
|
---|
1343 | Executes the SQL query \a sql. Returns true of the cursor is
|
---|
1344 | active, otherwise returns false.
|
---|
1345 | */
|
---|
1346 | bool Q3SqlCursor::exec(const QString & sql)
|
---|
1347 | {
|
---|
1348 | d->lastAt = QSql::BeforeFirst;
|
---|
1349 | QSqlQuery::exec(sql);
|
---|
1350 | return isActive();
|
---|
1351 | }
|
---|
1352 |
|
---|
1353 | /*!
|
---|
1354 | Protected virtual function which is called whenever a field needs
|
---|
1355 | to be calculated. If calculated fields are being used, derived
|
---|
1356 | classes must reimplement this function and return the appropriate
|
---|
1357 | value for field \a name. The default implementation returns an
|
---|
1358 | invalid QVariant.
|
---|
1359 |
|
---|
1360 | \sa setCalculated()
|
---|
1361 | */
|
---|
1362 |
|
---|
1363 | QVariant Q3SqlCursor::calculateField(const QString&)
|
---|
1364 | {
|
---|
1365 | return QVariant();
|
---|
1366 | }
|
---|
1367 |
|
---|
1368 | /*! \internal
|
---|
1369 | Ensure fieldlist is synced with query.
|
---|
1370 |
|
---|
1371 | */
|
---|
1372 |
|
---|
1373 | static QString qTrim(const QString& s)
|
---|
1374 | {
|
---|
1375 | QString result = s;
|
---|
1376 | int end = result.length() - 1;
|
---|
1377 | while (end >= 0 && result[end].isSpace()) // skip white space from end
|
---|
1378 | end--;
|
---|
1379 | result.truncate(end + 1);
|
---|
1380 | return result;
|
---|
1381 | }
|
---|
1382 |
|
---|
1383 | /*! \internal
|
---|
1384 | */
|
---|
1385 |
|
---|
1386 | void Q3SqlCursor::sync()
|
---|
1387 | {
|
---|
1388 | if (isActive() && isValid() && d->lastAt != at()) {
|
---|
1389 | d->lastAt = at();
|
---|
1390 | int i = 0;
|
---|
1391 | int j = 0;
|
---|
1392 | bool haveCalculatedFields = false;
|
---|
1393 | for (; i < count(); ++i) {
|
---|
1394 | if (!haveCalculatedFields && d->infoBuffer[i].isCalculated()) {
|
---|
1395 | haveCalculatedFields = true;
|
---|
1396 | }
|
---|
1397 | if (QSqlRecord::isGenerated(i)) {
|
---|
1398 | QVariant v = QSqlQuery::value(j);
|
---|
1399 | if ((v.type() == QVariant::String) &&
|
---|
1400 | d->infoBuffer[i].isTrim()) {
|
---|
1401 | v = qTrim(v.toString());
|
---|
1402 | }
|
---|
1403 | QSqlRecord::setValue(i, v);
|
---|
1404 | if (QSqlQuery::isNull(j))
|
---|
1405 | QSqlRecord::field(i).clear();
|
---|
1406 | j++;
|
---|
1407 | }
|
---|
1408 | }
|
---|
1409 | if (haveCalculatedFields) {
|
---|
1410 | for (i = 0; i < count(); ++i) {
|
---|
1411 | if (d->infoBuffer[i].isCalculated())
|
---|
1412 | QSqlRecord::setValue(i, calculateField(fieldName(i)));
|
---|
1413 | }
|
---|
1414 | }
|
---|
1415 | }
|
---|
1416 | }
|
---|
1417 |
|
---|
1418 | /*!
|
---|
1419 | Returns the value of field number \a i.
|
---|
1420 | */
|
---|
1421 |
|
---|
1422 | QVariant Q3SqlCursor::value(int i) const
|
---|
1423 | {
|
---|
1424 | const_cast<Q3SqlCursor *>(this)->sync();
|
---|
1425 | return QSqlRecord::value(i);
|
---|
1426 | }
|
---|
1427 |
|
---|
1428 | /*! \internal
|
---|
1429 | cursors should be filled with Q3SqlFieldInfos...
|
---|
1430 | */
|
---|
1431 | void Q3SqlCursor::append(const QSqlField& field)
|
---|
1432 | {
|
---|
1433 | append(Q3SqlFieldInfo(field));
|
---|
1434 | }
|
---|
1435 |
|
---|
1436 | /*!
|
---|
1437 | Returns true if the field \a i is NULL or if there is no field at
|
---|
1438 | position \a i; otherwise returns false.
|
---|
1439 |
|
---|
1440 | This is the same as calling QSqlRecord::isNull(\a i)
|
---|
1441 | */
|
---|
1442 | bool Q3SqlCursor::isNull(int i) const
|
---|
1443 | {
|
---|
1444 | const_cast<Q3SqlCursor *>(this)->sync();
|
---|
1445 | return QSqlRecord::isNull(i);
|
---|
1446 | }
|
---|
1447 | /*!
|
---|
1448 | \overload
|
---|
1449 |
|
---|
1450 | Returns true if the field called \a name is NULL or if there is no
|
---|
1451 | field called \a name; otherwise returns false.
|
---|
1452 |
|
---|
1453 | This is the same as calling QSqlRecord::isNull(\a name)
|
---|
1454 | */
|
---|
1455 | bool Q3SqlCursor::isNull(const QString& name) const
|
---|
1456 | {
|
---|
1457 | const_cast<Q3SqlCursor *>(this)->sync();
|
---|
1458 | return QSqlRecord::isNull(name);
|
---|
1459 | }
|
---|
1460 |
|
---|
1461 | /*! \internal */
|
---|
1462 | void Q3SqlCursor::setValue(int i, const QVariant& val)
|
---|
1463 | {
|
---|
1464 | sync();
|
---|
1465 | #ifdef QT_DEBUG
|
---|
1466 | qDebug("Q3SqlCursor::setValue(): This will not affect actual database values. Use primeInsert(), primeUpdate() or primeDelete().");
|
---|
1467 | #endif
|
---|
1468 | QSqlRecord::setValue(i, val);
|
---|
1469 | }
|
---|
1470 |
|
---|
1471 | /*! \internal */
|
---|
1472 | bool Q3SqlCursor::seek(int i, bool relative)
|
---|
1473 | {
|
---|
1474 | bool res = QSqlQuery::seek(i, relative);
|
---|
1475 | sync();
|
---|
1476 | return res;
|
---|
1477 | }
|
---|
1478 |
|
---|
1479 | /*! \internal */
|
---|
1480 | bool Q3SqlCursor::next()
|
---|
1481 | {
|
---|
1482 | bool res = QSqlQuery::next();
|
---|
1483 | sync();
|
---|
1484 | return res;
|
---|
1485 | }
|
---|
1486 |
|
---|
1487 | /*!
|
---|
1488 | \fn Q3SqlCursor::previous()
|
---|
1489 |
|
---|
1490 | \internal
|
---|
1491 | */
|
---|
1492 |
|
---|
1493 | /*! \internal */
|
---|
1494 | bool Q3SqlCursor::prev()
|
---|
1495 | {
|
---|
1496 | bool res = QSqlQuery::previous();
|
---|
1497 | sync();
|
---|
1498 | return res;
|
---|
1499 | }
|
---|
1500 |
|
---|
1501 | /*! \internal */
|
---|
1502 | bool Q3SqlCursor::first()
|
---|
1503 | {
|
---|
1504 | bool res = QSqlQuery::first();
|
---|
1505 | sync();
|
---|
1506 | return res;
|
---|
1507 | }
|
---|
1508 |
|
---|
1509 | /*! \internal */
|
---|
1510 | bool Q3SqlCursor::last()
|
---|
1511 | {
|
---|
1512 | bool res = QSqlQuery::last();
|
---|
1513 | sync();
|
---|
1514 | return res;
|
---|
1515 | }
|
---|
1516 |
|
---|
1517 | QT_END_NAMESPACE
|
---|
1518 |
|
---|
1519 | #endif
|
---|