/src/qt3support/sql/q3sqlcursor.cpp
https://bitbucket.org/ultra_iter/qt-vtl · C++ · 1519 lines · 695 code · 140 blank · 684 comment · 125 complexity · 5a68709307fdc926baca8fb5e7081fa9 MD5 · raw file
- /****************************************************************************
- **
- ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
- ** All rights reserved.
- ** Contact: Nokia Corporation (qt-info@nokia.com)
- **
- ** This file is part of the Qt3Support module of the Qt Toolkit.
- **
- ** $QT_BEGIN_LICENSE:LGPL$
- ** GNU Lesser General Public License Usage
- ** This file may be used under the terms of the GNU Lesser General Public
- ** License version 2.1 as published by the Free Software Foundation and
- ** appearing in the file LICENSE.LGPL included in the packaging of this
- ** file. Please review the following information to ensure the GNU Lesser
- ** General Public License version 2.1 requirements will be met:
- ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
- **
- ** In addition, as a special exception, Nokia gives you certain additional
- ** rights. These rights are described in the Nokia Qt LGPL Exception
- ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
- **
- ** GNU General Public License Usage
- ** Alternatively, this file may be used under the terms of the GNU General
- ** Public License version 3.0 as published by the Free Software Foundation
- ** and appearing in the file LICENSE.GPL included in the packaging of this
- ** file. Please review the following information to ensure the GNU General
- ** Public License version 3.0 requirements will be met:
- ** http://www.gnu.org/copyleft/gpl.html.
- **
- ** Other Usage
- ** Alternatively, this file may be used in accordance with the terms and
- ** conditions contained in a signed written agreement between you and Nokia.
- **
- **
- **
- **
- **
- ** $QT_END_LICENSE$
- **
- ****************************************************************************/
- #include <qplatformdefs.h>
- #include "q3sqlcursor.h"
- #ifndef QT_NO_SQL
- #include "qsqldriver.h"
- #include "qsqlresult.h"
- #include "qdatetime.h"
- #include "qsqldatabase.h"
- #include "qsql.h"
- #include "q3sqlrecordinfo.h"
- #include "q3sqlfieldinfo.h"
- QT_BEGIN_NAMESPACE
- class Q3SqlCursorPrivate
- {
- public:
- Q3SqlCursorPrivate(const QString& name, QSqlDatabase sdb)
- : lastAt(QSql::BeforeFirst), nm(name), srt(name), md(0), db(sdb), q(0)
- {}
- ~Q3SqlCursorPrivate()
- {
- delete q;
- }
- QSqlQuery* query()
- {
- if (!q)
- q = new QSqlQuery(QString(), db);
- return q;
- }
- int lastAt;
- QString nm; //name
- QSqlIndex srt; //sort
- QString ftr; //filter
- int md; //mode
- QSqlIndex priIndx; //primary index
- QSqlRecord editBuffer;
- // the primary index as it was before the user changed the values in editBuffer
- QString editIndex;
- Q3SqlRecordInfo infoBuffer;
- QSqlDatabase db;
- QSqlQuery *q;
- };
- QString qOrderByClause(const QSqlIndex & i, const QString& prefix = QString())
- {
- QString str;
- int k = i.count();
- if(k == 0)
- return QString();
- str = QLatin1String(" order by ") + i.toString(prefix);
- return str;
- }
- QString qWhereClause(const QString& prefix, QSqlField* field, const QSqlDriver* driver)
- {
- QString f;
- if (field && driver) {
- if (!prefix.isEmpty())
- f += prefix + QLatin1Char('.');
- f += field->name();
- if (field->isNull()) {
- f += QLatin1String(" IS NULL");
- } else {
- f += QLatin1String(" = ") + driver->formatValue(field);
- }
- }
- return f;
- }
- QString qWhereClause(QSqlRecord* rec, const QString& prefix, const QString& sep,
- const QSqlDriver* driver)
- {
- static QString blank(QLatin1Char(' '));
- QString filter;
- bool separator = false;
- for (int j = 0; j < rec->count(); ++j) {
- QSqlField f = rec->field(j);
- if (rec->isGenerated(j)) {
- if (separator)
- filter += sep + blank;
- filter += qWhereClause(prefix, &f, driver);
- filter += blank;
- separator = true;
- }
- }
- return filter;
- }
- /*!
- \class Q3SqlCursor
- \brief The Q3SqlCursor class provides browsing and editing of SQL
- tables and views.
- \compat
- A Q3SqlCursor is a database record (see \l QSqlRecord) that
- corresponds to a table or view within an SQL database (see \l
- QSqlDatabase). There are two buffers in a cursor, one used for
- browsing and one used for editing records. Each buffer contains a
- list of fields which correspond to the fields in the table or
- view.
- When positioned on a valid record, the browse buffer contains the
- values of the current record's fields from the database. The edit
- buffer is separate, and is used for editing existing records and
- inserting new records.
- For browsing data, a cursor must first select() data from the
- database. After a successful select() the cursor is active
- (isActive() returns true), but is initially not positioned on a
- valid record (isValid() returns false). To position the cursor on
- a valid record, use one of the navigation functions, next(),
- previous(), first(), last(), or seek(). Once positioned on a valid
- record, data can be retrieved from the browse buffer using
- value(). If a navigation function is not successful, it returns
- false, the cursor will no longer be positioned on a valid record
- and the values returned by value() are undefined.
- For example:
- \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 0
- In the above example, a cursor is created specifying a table or
- view name in the database. Then, select() is called, which can be
- optionally parameterised to filter and order the records
- retrieved. Each record in the cursor is retrieved using next().
- When next() returns false, there are no more records to process,
- and the loop terminates.
- For editing records (rows of data), a cursor contains a separate
- edit buffer which is independent of the fields used when browsing.
- The functions insert(), update() and del() operate on the edit
- buffer. This allows the cursor to be repositioned to other
- records while simultaneously maintaining a separate buffer for
- edits. You can get a pointer to the edit buffer using
- editBuffer(). The primeInsert(), primeUpdate() and primeDelete()
- functions also return a pointer to the edit buffer and prepare it
- for insert, update and delete respectively. Edit operations only
- affect a single row at a time. Note that update() and del()
- require that the table or view contain a primaryIndex() to ensure
- that edit operations affect a unique record within the database.
- For example:
- \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 1
- To edit an existing database record, first move to the record you
- wish to update. Call primeUpdate() to get the pointer to the
- cursor's edit buffer. Then use this pointer to modify the values
- in the edit buffer. Finally, call update() to save the changes to
- the database. The values in the edit buffer will be used to
- locate the appropriate record when updating the database (see
- primaryIndex()).
- Similarly, when deleting an existing database record, first move
- to the record you wish to delete. Then, call primeDelete() to get
- the pointer to the edit buffer. Finally, call del() to delete the
- record from the database. Again, the values in the edit buffer
- will be used to locate and delete the appropriate record.
- To insert a new record, call primeInsert() to get the pointer to
- the edit buffer. Use this pointer to populate the edit buffer
- with new values and then insert() the record into the database.
- After calling insert(), update() or del(), the cursor is no longer
- positioned on a valid record and can no longer be navigated
- (isValid() return false). The reason for this is that any changes
- made to the database will not be visible until select() is called
- to refresh the cursor. You can change this behavior by passing
- false to insert(), update() or del() which will prevent the cursor
- from becoming invalid. The edits will still not be visible when
- navigating the cursor until select() is called.
- Q3SqlCursor contains virtual methods which allow editing behavior
- to be customized by subclasses. This allows custom cursors to be
- created that encapsulate the editing behavior of a database table
- for an entire application. For example, a cursor can be customized
- to always auto-number primary index fields, or provide fields with
- suitable default values, when inserting new records. Q3SqlCursor
- generates SQL statements which are sent to the database engine;
- you can control which fields are included in these statements
- using setGenerated().
- Note that Q3SqlCursor does not inherit from QObject. This means
- that you are responsible for destroying instances of this class
- yourself. However if you create a Q3SqlCursor and use it in a
- \l Q3DataTable, \l Q3DataBrowser or a \l Q3DataView these classes will
- usually take ownership of the cursor and destroy it when they
- don't need it anymore. The documentation for Q3DataTable,
- Q3DataBrowser and Q3DataView explicitly states which calls take
- ownership of the cursor.
- */
- /*!
- \enum Q3SqlCursor::Mode
- This enum type describes how Q3SqlCursor operates on records in the
- database.
- \value ReadOnly the cursor can only SELECT records from the
- database.
- \value Insert the cursor can INSERT records into the database.
- \value Update the cursor can UPDATE records in the database.
- \value Delete the cursor can DELETE records from the database.
- \value Writable the cursor can INSERT, UPDATE and DELETE records
- in the database.
- */
- /*!
- \fn QVariant Q3SqlCursor::value(const QString &name) const
- \overload
- Returns the value of the field named \a name.
- */
- /*!
- \fn void Q3SqlCursor::setValue(const QString &name, const QVariant &val)
- \overload
- Sets the value for the field named \a name to \a val.
- */
- /*!
- Constructs a cursor on database \a db using table or view \a name.
- If \a autopopulate is true (the default), the \a name of the
- cursor must correspond to an existing table or view name in the
- database so that field information can be automatically created.
- If the table or view does not exist, the cursor will not be
- functional.
- The cursor is created with an initial mode of Q3SqlCursor::Writable
- (meaning that records can be inserted, updated or deleted using
- the cursor). If the cursor does not have a unique primary index,
- update and deletes cannot be performed.
- Note that \a autopopulate refers to populating the cursor with
- meta-data, e.g. the names of the table's fields, not with
- retrieving data. The select() function is used to populate the
- cursor with data.
- \sa setName() setMode()
- */
- Q3SqlCursor::Q3SqlCursor(const QString & name, bool autopopulate, QSqlDatabase db)
- : QSqlRecord(), QSqlQuery(QString(), db)
- {
- d = new Q3SqlCursorPrivate(name, db);
- setMode(Writable);
- if (!d->nm.isEmpty())
- setName(d->nm, autopopulate);
- }
- /*!
- Constructs a copy of \a other.
- */
- Q3SqlCursor::Q3SqlCursor(const Q3SqlCursor & other)
- : QSqlRecord(other), QSqlQuery(other)
- {
- d = new Q3SqlCursorPrivate(other.d->nm, other.d->db);
- d->lastAt = other.d->lastAt;
- d->nm = other.d->nm;
- d->srt = other.d->srt;
- d->ftr = other.d->ftr;
- d->priIndx = other.d->priIndx;
- d->editBuffer = other.d->editBuffer;
- d->infoBuffer = other.d->infoBuffer;
- d->q = 0; // do not share queries
- setMode(other.mode());
- }
- /*!
- Destroys the object and frees any allocated resources.
- */
- Q3SqlCursor::~Q3SqlCursor()
- {
- delete d;
- }
- /*!
- Sets the cursor equal to \a other.
- */
- Q3SqlCursor& Q3SqlCursor::operator=(const Q3SqlCursor& other)
- {
- QSqlRecord::operator=(other);
- QSqlQuery::operator=(other);
- delete d;
- d = new Q3SqlCursorPrivate(other.d->nm, other.d->db);
- d->lastAt = other.d->lastAt;
- d->nm = other.d->nm;
- d->srt = other.d->srt;
- d->ftr = other.d->ftr;
- d->priIndx = other.d->priIndx;
- d->editBuffer = other.d->editBuffer;
- d->infoBuffer = other.d->infoBuffer;
- d->q = 0; // do not share queries
- setMode(other.mode());
- return *this;
- }
- /*!
- Sets the current sort to \a sort. Note that no new records are
- selected. To select new records, use select(). The \a sort will
- apply to any subsequent select() calls that do not explicitly
- specify a sort.
- */
- void Q3SqlCursor::setSort(const QSqlIndex& sort)
- {
- d->srt = sort;
- }
- /*!
- Returns the current sort, or an empty index if there is no current
- sort.
- */
- QSqlIndex Q3SqlCursor::sort() const
- {
- return d->srt;
- }
- /*!
- Sets the current filter to \a filter. Note that no new records are
- selected. To select new records, use select(). The \a filter will
- apply to any subsequent select() calls that do not explicitly
- specify a filter.
- The filter is a SQL \c WHERE clause without the keyword 'WHERE',
- e.g. \c{name='Dave'} which will be processed by the DBMS.
- */
- void Q3SqlCursor::setFilter(const QString& filter)
- {
- d->ftr = filter;
- }
- /*!
- Returns the current filter, or an empty string if there is no
- current filter.
- */
- QString Q3SqlCursor::filter() const
- {
- return d->ftr;
- }
- /*!
- Sets the name of the cursor to \a name. If \a autopopulate is true
- (the default), the \a name must correspond to a valid table or
- view name in the database. Also, note that all references to the
- cursor edit buffer become invalidated when fields are
- auto-populated. See the Q3SqlCursor constructor documentation for
- more information.
- */
- void Q3SqlCursor::setName(const QString& name, bool autopopulate)
- {
- d->nm = name;
- if (autopopulate) {
- if (driver()) {
- d->infoBuffer = driver()->record(name);
- *this = d->infoBuffer.toRecord();
- d->editBuffer = *this;
- d->priIndx = driver()->primaryIndex(name);
- }
- if (isEmpty())
- qWarning("Q3SqlCursor::setName: unable to build record, does '%s' exist?", name.latin1());
- }
- }
- /*!
- Returns the name of the cursor.
- */
- QString Q3SqlCursor::name() const
- {
- return d->nm;
- }
- /*! \internal
- */
- QString Q3SqlCursor::toString(const QString& prefix, const QString& sep) const
- {
- QString pflist;
- QString pfix = prefix.isEmpty() ? prefix : prefix + QLatin1Char('.');
- bool comma = false;
- for (int i = 0; i < count(); ++i) {
- const QString fname = fieldName(i);
- if (isGenerated(i)) {
- if(comma)
- pflist += sep + QLatin1Char(' ');
- pflist += pfix + driver()->escapeIdentifier(fname, QSqlDriver::FieldName);
- comma = true;
- }
- }
- return pflist;
- }
- /*!
- \internal
- Assigns the record \a list.
- */
- QSqlRecord & Q3SqlCursor::operator=(const QSqlRecord & list)
- {
- return QSqlRecord::operator=(list);
- }
- /*!
- Append a copy of field \a fieldInfo to the end of the cursor. Note
- that all references to the cursor edit buffer become invalidated.
- */
- void Q3SqlCursor::append(const Q3SqlFieldInfo& fieldInfo)
- {
- d->editBuffer.append(fieldInfo.toField());
- d->infoBuffer.append(fieldInfo);
- QSqlRecord::append(fieldInfo.toField());
- }
- /*!
- Removes all fields from the cursor. Note that all references to
- the cursor edit buffer become invalidated.
- */
- void Q3SqlCursor::clear()
- {
- d->editBuffer.clear();
- d->infoBuffer.clear();
- QSqlRecord::clear();
- }
- /*!
- Insert a copy of \a fieldInfo at position \a pos. If a field
- already exists at \a pos, it is removed. Note that all references
- to the cursor edit buffer become invalidated.
- */
- void Q3SqlCursor::insert(int pos, const Q3SqlFieldInfo& fieldInfo)
- {
- d->editBuffer.replace(pos, fieldInfo.toField());
- d->infoBuffer[pos] = fieldInfo;
- QSqlRecord::replace(pos, fieldInfo.toField());
- }
- /*!
- Removes the field at \a pos. If \a pos does not exist, nothing
- happens. Note that all references to the cursor edit buffer become
- invalidated.
- */
- void Q3SqlCursor::remove(int pos)
- {
- d->editBuffer.remove(pos);
- d->infoBuffer[pos] = Q3SqlFieldInfo();
- QSqlRecord::remove(pos);
- }
- /*!
- Sets the generated flag for the field \a name to \a generated. If
- the field does not exist, nothing happens. Only fields that have
- \a generated set to true are included in the SQL that is
- generated by insert(), update() or del().
- */
- void Q3SqlCursor::setGenerated(const QString& name, bool generated)
- {
- int pos = indexOf(name);
- if (pos == -1)
- return;
- QSqlRecord::setGenerated(name, generated);
- d->editBuffer.setGenerated(name, generated);
- d->infoBuffer[pos].setGenerated(generated);
- }
- /*!
- \overload
- Sets the generated flag for the field \a i to \a generated.
- */
- void Q3SqlCursor::setGenerated(int i, bool generated)
- {
- if (i < 0 || i >= (int)d->infoBuffer.count())
- return;
- QSqlRecord::setGenerated(i, generated);
- d->editBuffer.setGenerated(i, generated);
- d->infoBuffer[i].setGenerated(generated);
- }
- /*!
- Returns the primary index associated with the cursor as defined in
- the database, or an empty index if there is no primary index. If
- \a setFromCursor is true (the default), the index fields are
- populated with the corresponding values in the cursor's current
- record.
- */
- QSqlIndex Q3SqlCursor::primaryIndex(bool setFromCursor) const
- {
- if (setFromCursor) {
- for (int i = 0; i < d->priIndx.count(); ++i) {
- const QString fn = d->priIndx.fieldName(i);
- if (contains(fn))
- d->priIndx.setValue(i, QSqlRecord::value(fn));
- }
- }
- return d->priIndx;
- }
- /*!
- Sets the primary index associated with the cursor to the index \a
- idx. Note that this index must contain a field or set of fields
- which identify a unique record within the underlying database
- table or view so that update() and del() will execute as expected.
- \sa update() del()
- */
- void Q3SqlCursor::setPrimaryIndex(const QSqlIndex& idx)
- {
- d->priIndx = idx;
- }
- /*!
- Returns an index composed of \a fieldNames, all in ASCending
- order. Note that all field names must exist in the cursor,
- otherwise an empty index is returned.
- \sa QSqlIndex
- */
- QSqlIndex Q3SqlCursor::index(const QStringList& fieldNames) const
- {
- QSqlIndex idx;
- for (QStringList::ConstIterator it = fieldNames.begin(); it != fieldNames.end(); ++it) {
- QSqlField f = field((*it));
- if (!f.isValid()) { /* all fields must exist */
- idx.clear();
- break;
- }
- idx.append(f);
- }
- return idx;
- }
- /*!
- \overload
- Returns an index based on \a fieldName.
- */
- QSqlIndex Q3SqlCursor::index(const QString& fieldName) const
- {
- QStringList fl(fieldName);
- return index(fl);
- }
- /*!
- Selects all fields in the cursor from the database matching the
- filter criteria \a filter. The data is returned in the order
- specified by the index \a sort. Returns true if the data was
- successfully selected; otherwise returns false.
- The \a filter is a string containing a SQL \c WHERE clause but
- without the 'WHERE' keyword. The cursor is initially positioned at
- an invalid row after this function is called. To move to a valid
- row, use seek(), first(), last(), previous() or next().
- Example:
- \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 2
- The filter will apply to any subsequent select() calls that do not
- explicitly specify another filter. Similarly the sort will apply
- to any subsequent select() calls that do not explicitly specify
- another sort.
- \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 3
- */
- bool Q3SqlCursor::select(const QString & filter, const QSqlIndex & sort)
- {
- QString fieldList(toString(d->nm));
- if (fieldList.isEmpty())
- return false;
- QString str(QLatin1String("select ") + fieldList);
- str += QLatin1String(" from ") + d->nm;
- if (!filter.isEmpty()) {
- d->ftr = filter;
- str += QLatin1String(" where ") + filter;
- } else
- d->ftr.clear();
- if (sort.count() > 0)
- str += QLatin1String(" order by ") + sort.toString(d->nm);
- d->srt = sort;
- return exec(str);
- }
- /*!
- \overload
- Selects all fields in the cursor from the database. The rows are
- returned in the order specified by the last call to setSort() or
- the last call to select() that specified a sort, whichever is the
- most recent. If there is no current sort, the order in which the
- rows are returned is undefined. The records are filtered according
- to the filter specified by the last call to setFilter() or the
- last call to select() that specified a filter, whichever is the
- most recent. If there is no current filter, all records are
- returned. The cursor is initially positioned at an invalid row. To
- move to a valid row, use seek(), first(), last(), previous() or
- next().
- \sa setSort() setFilter()
- */
- bool Q3SqlCursor::select()
- {
- return select(filter(), sort());
- }
- /*!
- \overload
- Selects all fields in the cursor from the database. The data is
- returned in the order specified by the index \a sort. The records
- are filtered according to the filter specified by the last call to
- setFilter() or the last call to select() that specified a filter,
- whichever is the most recent. The cursor is initially positioned
- at an invalid row. To move to a valid row, use seek(), first(),
- last(), previous() or next().
- */
- bool Q3SqlCursor::select(const QSqlIndex& sort)
- {
- return select(filter(), sort);
- }
- /*!
- \overload
- Selects all fields in the cursor matching the filter index \a
- filter. The data is returned in the order specified by the index
- \a sort. The \a filter index works by constructing a WHERE clause
- using the names of the fields from the \a filter and their values
- from the current cursor record. The cursor is initially positioned
- at an invalid row. To move to a valid row, use seek(), first(),
- last(), previous() or next(). This function is useful, for example,
- for retrieving data based upon a table's primary index:
- \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 4
- In this example the QSqlIndex, pk, is used for two different
- purposes. When used as the filter (first) argument, the field
- names it contains are used to construct the WHERE clause, each set
- to the current cursor value, \c{WHERE id=10}, in this case. When
- used as the sort (second) argument the field names it contains are
- used for the ORDER BY clause, \c{ORDER BY id} in this example.
- */
- bool Q3SqlCursor::select(const QSqlIndex & filter, const QSqlIndex & sort)
- {
- return select(toString(filter, this, d->nm, QString(QLatin1Char('=')), QLatin1String("and")), sort);
- }
- /*!
- Sets the cursor mode to \a mode. This value can be an OR'ed
- combination of \l Q3SqlCursor::Mode values. The default mode for a
- cursor is Q3SqlCursor::Writable.
- \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 5
- */
- void Q3SqlCursor::setMode(int mode)
- {
- d->md = mode;
- }
- /*!
- Returns the current cursor mode.
- \sa setMode()
- */
- int Q3SqlCursor::mode() const
- {
- return d->md;
- }
- /*!
- Sets field \a name to \a calculated. If the field \a name does not
- exist, nothing happens. The value of a calculated field is set by
- the calculateField() virtual function which you must reimplement
- (or the field value will be an invalid QVariant). Calculated
- fields do not appear in generated SQL statements sent to the
- database.
- \sa calculateField()
- */
- void Q3SqlCursor::setCalculated(const QString& name, bool calculated)
- {
- int pos = indexOf(name);
- if (pos < 0)
- return;
- d->infoBuffer[pos].setCalculated(calculated);
- if (calculated)
- setGenerated(pos, false);
- }
- /*!
- Returns true if the field \a name exists and is calculated;
- otherwise returns false.
- \sa setCalculated()
- */
- bool Q3SqlCursor::isCalculated(const QString& name) const
- {
- int pos = indexOf(name);
- if (pos < 0)
- return false;
- return d->infoBuffer[pos].isCalculated();
- }
- /*!
- Sets field \a{name}'s trimmed status to \a trim. If the field \a
- name does not exist, nothing happens.
- When a trimmed field of type string is read from the
- database any trailing (right-most) spaces are removed.
- \sa isTrimmed() QVariant
- */
- void Q3SqlCursor::setTrimmed(const QString& name, bool trim)
- {
- int pos = indexOf(name);
- if (pos < 0)
- return;
- d->infoBuffer[pos].setTrim(trim);
- }
- /*!
- Returns true if the field \a name exists and is trimmed; otherwise
- returns false.
- When a trimmed field of type string or cstring is read from the
- database any trailing (right-most) spaces are removed.
- \sa setTrimmed()
- */
- bool Q3SqlCursor::isTrimmed(const QString& name) const
- {
- int pos = indexOf(name);
- if (pos < 0)
- return false;
- return d->infoBuffer[pos].isTrim();
- }
- /*!
- Returns true if the cursor is read-only; otherwise returns false.
- The default is false. Read-only cursors cannot be edited using
- insert(), update() or del().
- \sa setMode()
- */
- bool Q3SqlCursor::isReadOnly() const
- {
- return d->md == 0;
- }
- /*!
- Returns true if the cursor will perform inserts; otherwise returns
- false.
- \sa setMode()
- */
- bool Q3SqlCursor::canInsert() const
- {
- return ((d->md & Insert) == Insert) ;
- }
- /*!
- Returns true if the cursor will perform updates; otherwise returns
- false.
- \sa setMode()
- */
- bool Q3SqlCursor::canUpdate() const
- {
- return ((d->md & Update) == Update) ;
- }
- /*!
- Returns true if the cursor will perform deletes; otherwise returns
- false.
- \sa setMode()
- */
- bool Q3SqlCursor::canDelete() const
- {
- return ((d->md & Delete) == Delete) ;
- }
- /*!
- \overload
- Returns a formatted string composed of the \a prefix (e.g. table
- or view name), ".", the \a field name, the \a fieldSep and the
- field value. If the \a prefix is empty then the string will begin
- with the \a field name. This function is useful for generating SQL
- statements.
- */
- QString Q3SqlCursor::toString(const QString& prefix, QSqlField* field, const QString& fieldSep) const
- {
- QString f;
- if (field && driver()) {
- f = (prefix.length() > 0 ? prefix + QLatin1Char('.') : QString()) + driver()->escapeIdentifier(field->name(), QSqlDriver::FieldName);
- f += QLatin1Char(' ') + fieldSep + QLatin1Char(' ');
- if (field->isNull()) {
- f += QLatin1String("NULL");
- } else {
- f += driver()->formatValue(field);
- }
- }
- return f;
- }
- /*!
- Returns a formatted string composed of all the fields in \a rec.
- Each field is composed of the \a prefix (e.g. table or view name),
- ".", the field name, the \a fieldSep and the field value. If the
- \a prefix is empty then each field will begin with the field name.
- The fields are then joined together separated by \a sep. Fields
- where isGenerated() returns false are not included. This function
- is useful for generating SQL statements.
- */
- QString Q3SqlCursor::toString(QSqlRecord* rec, const QString& prefix, const QString& fieldSep,
- const QString& sep) const
- {
- static QString blank(QLatin1Char(' '));
- QString filter;
- bool separator = false;
- for (int j = 0; j < count(); ++j) {
- QSqlField f = rec->field(j);
- if (rec->isGenerated(j)) {
- if (separator)
- filter += sep + blank;
- filter += toString(prefix, &f, fieldSep);
- filter += blank;
- separator = true;
- }
- }
- return filter;
- }
- /*!
- \overload
- Returns a formatted string composed of all the fields in the index
- \a i. Each field is composed of the \a prefix (e.g. table or view
- name), ".", the field name, the \a fieldSep and the field value.
- If the \a prefix is empty then each field will begin with the field
- name. The field values are taken from \a rec. The fields are then
- joined together separated by \a sep. Fields where isGenerated()
- returns false are ignored. This function is useful for generating
- SQL statements.
- */
- QString Q3SqlCursor::toString(const QSqlIndex& i, QSqlRecord* rec, const QString& prefix,
- const QString& fieldSep, const QString& sep) const
- {
- QString filter;
- bool separator = false;
- for(int j = 0; j < i.count(); ++j){
- if (rec->isGenerated(j)) {
- if(separator) {
- filter += QLatin1Char(' ') + sep + QLatin1Char(' ') ;
- }
- QString fn = i.fieldName(j);
- QSqlField f = rec->field(fn);
- filter += toString(prefix, &f, fieldSep);
- separator = true;
- }
- }
- return filter;
- }
- /*!
- Inserts the current contents of the cursor's edit record buffer
- into the database, if the cursor allows inserts. Returns the
- number of rows affected by the insert. For error information, use
- lastError().
- If \a invalidate is true (the default), the cursor will no longer
- be positioned on a valid record and can no longer be navigated. A
- new select() call must be made before navigating to a valid
- record.
- \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 6
- In the above example, a cursor is created on the 'prices' table
- and a pointer to the insert buffer is acquired using primeInsert().
- Each field's value is set to the desired value and then insert()
- is called to insert the data into the database. Remember: all edit
- operations (insert(), update() and delete()) operate on the
- contents of the cursor edit buffer and not on the contents of the
- cursor itself.
- \sa setMode() lastError()
- */
- int Q3SqlCursor::insert(bool invalidate)
- {
- if ((d->md & Insert) != Insert || !driver())
- return false;
- int k = d->editBuffer.count();
- if (k == 0)
- return 0;
- QString fList;
- QString vList;
- bool comma = false;
- // use a prepared query if the driver supports it
- if (driver()->hasFeature(QSqlDriver::PreparedQueries)) {
- int cnt = 0;
- bool oraStyle = driver()->hasFeature(QSqlDriver::NamedPlaceholders);
- for(int j = 0; j < k; ++j) {
- QSqlField f = d->editBuffer.field(j);
- if (d->editBuffer.isGenerated(j)) {
- if (comma) {
- fList += QLatin1Char(',');
- vList += QLatin1Char(',');
- }
- fList += driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName);
- vList += (oraStyle == true) ? QLatin1String(":f") + QString::number(cnt) : QString(QLatin1Char('?'));
- cnt++;
- comma = true;
- }
- }
- if (!comma) {
- return 0;
- }
- QString str;
- str.append(QLatin1String("insert into ")).append(name())
- .append(QLatin1String(" (")).append(fList)
- .append(QLatin1String(") values (")).append(vList). append(QLatin1Char(')'));
- return applyPrepared(str, invalidate);
- } else {
- for(int j = 0; j < k; ++j) {
- QSqlField f = d->editBuffer.field(j);
- if (d->editBuffer.isGenerated(j)) {
- if (comma) {
- fList += QLatin1Char(',');
- vList += QLatin1Char(',');
- }
- fList += driver()->escapeIdentifier(f.name(), QSqlDriver::FieldName);
- vList += driver()->formatValue(&f);
- comma = true;
- }
- }
- if (!comma) {
- // no valid fields found
- return 0;
- }
- QString str;
- str.append(QLatin1String("insert into ")).append(name()).append(QLatin1String(" ("))
- .append(fList).append(QLatin1String(") values (")).append(vList). append (QLatin1String(")"));
- return apply(str, invalidate);
- }
- }
- /*!
- Returns the current internal edit buffer. If \a copy is true (the
- default is false), the current cursor field values are first
- copied into the edit buffer. The edit buffer is valid as long as
- the cursor remains valid. The cursor retains ownership of the
- returned pointer, so it must not be deleted or modified.
- \sa primeInsert(), primeUpdate() primeDelete()
- */
- QSqlRecord* Q3SqlCursor::editBuffer(bool copy)
- {
- sync();
- if (copy) {
- for(int i = 0; i < d->editBuffer.count(); i++) {
- if (QSqlRecord::isNull(i)) {
- d->editBuffer.setNull(i);
- } else {
- d->editBuffer.setValue(i, value(i));
- }
- }
- }
- return &d->editBuffer;
- }
- /*!
- This function primes the edit buffer's field values for update and
- returns the edit buffer. The default implementation copies the
- field values from the current cursor record into the edit buffer
- (therefore, this function is equivalent to calling editBuffer(
- true)). The cursor retains ownership of the returned pointer, so
- it must not be deleted or modified.
- \sa editBuffer() update()
- */
- QSqlRecord* Q3SqlCursor::primeUpdate()
- {
- // memorize the primary keys as they were before the user changed the values in editBuffer
- QSqlRecord* buf = editBuffer(true);
- QSqlIndex idx = primaryIndex(false);
- if (!idx.isEmpty())
- d->editIndex = toString(idx, buf, d->nm, QString(QLatin1Char('=')), QLatin1String("and"));
- else
- d->editIndex = qWhereClause(buf, d->nm, QLatin1String("and"), driver());
- return buf;
- }
- /*!
- This function primes the edit buffer's field values for delete and
- returns the edit buffer. The default implementation copies the
- field values from the current cursor record into the edit buffer
- (therefore, this function is equivalent to calling editBuffer(
- true)). The cursor retains ownership of the returned pointer, so
- it must not be deleted or modified.
- \sa editBuffer() del()
- */
- QSqlRecord* Q3SqlCursor::primeDelete()
- {
- return editBuffer(true);
- }
- /*!
- This function primes the edit buffer's field values for insert and
- returns the edit buffer. The default implementation clears all
- field values in the edit buffer. The cursor retains ownership of
- the returned pointer, so it must not be deleted or modified.
- \sa editBuffer() insert()
- */
- QSqlRecord* Q3SqlCursor::primeInsert()
- {
- d->editBuffer.clearValues();
- return &d->editBuffer;
- }
- /*!
- Updates the database with the current contents of the edit buffer.
- Returns the number of records which were updated.
- For error information, use lastError().
- Only records which meet the filter criteria specified by the
- cursor's primary index are updated. If the cursor does not contain
- a primary index, no update is performed and 0 is returned.
- If \a invalidate is true (the default), the current cursor can no
- longer be navigated. A new select() call must be made before you
- can move to a valid record. For example:
- \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 7
- In the above example, a cursor is created on the 'prices' table
- and is positioned on the record to be updated. Then a pointer to
- the cursor's edit buffer is acquired using primeUpdate(). A new
- value is calculated and placed into the edit buffer with the
- setValue() call. Finally, an update() call is made on the cursor
- which uses the tables's primary index to update the record in the
- database with the contents of the cursor's edit buffer. Remember:
- all edit operations (insert(), update() and delete()) operate on
- the contents of the cursor edit buffer and not on the contents of
- the cursor itself.
- Note that if the primary index does not uniquely distinguish
- records the database may be changed into an inconsistent state.
- \sa setMode() lastError()
- */
- int Q3SqlCursor::update(bool invalidate)
- {
- if (d->editIndex.isEmpty())
- return 0;
- return update(d->editIndex, invalidate);
- }
- /*!
- \overload
- Updates the database with the current contents of the cursor edit
- buffer using the specified \a filter. Returns the number of
- records which were updated.
- For error information, use lastError().
- Only records which meet the filter criteria are updated, otherwise
- all records in the table are updated.
- If \a invalidate is true (the default), the cursor can no longer
- be navigated. A new select() call must be made before you can move
- to a valid record.
- \sa primeUpdate() setMode() lastError()
- */
- int Q3SqlCursor::update(const QString & filter, bool invalidate)
- {
- if ((d->md & Update) != Update) {
- return false;
- }
- int k = count();
- if (k == 0) {
- return 0;
- }
-
- // use a prepared query if the driver supports it
- if (driver()->hasFeature(QSqlDriver::PreparedQueries)) {
- QString fList;
- bool comma = false;
- int cnt = 0;
- bool oraStyle = driver()->hasFeature(QSqlDriver::NamedPlaceholders);
- for(int j = 0; j < k; ++j) {
- QSqlField f = d->editBuffer.field(j);
- if (d->editBuffer.isGenerated(j)) {
- if (comma) {
- fList += QLatin1Char(',');
- }
- fList += f.name() + QLatin1String(" = ") + (oraStyle == true ? QLatin1String(":f") + QString::number(cnt) : QString(QLatin1Char('?')));
- cnt++;
- comma = true;
- }
- }
- if (!comma) {
- return 0;
- }
- QString str(QLatin1String("update ") + name() + QLatin1String(" set ") + fList);
- if (filter.length()) {
- str+= QLatin1String(" where ") + filter;
- }
- return applyPrepared(str, invalidate);
- } else {
- QString str = QLatin1String("update ") + name();
- str += QLatin1String(" set ") + toString(&d->editBuffer, QString(), QString(QLatin1Char('=')), QString(QLatin1Char(',')));
- if (filter.length()) {
- str+= QLatin1String(" where ") + filter;
- }
- return apply(str, invalidate);
- }
- }
- /*!
- Deletes a record from the database using the cursor's primary
- index and the contents of the cursor edit buffer. Returns the
- number of records which were deleted.
- For error information, use lastError().
- Only records which meet the filter criteria specified by the
- cursor's primary index are deleted. If the cursor does not contain
- a primary index, no delete is performed and 0 is returned. If \a
- invalidate is true (the default), the current cursor can no longer
- be navigated. A new select() call must be made before you can move
- to a valid record. For example:
- \snippet doc/src/snippets/code/src_qt3support_sql_q3sqlcursor.cpp 8
- In the above example, a cursor is created on the 'prices' table
- and positioned to the record to be deleted. First primeDelete() is
- called to populate the edit buffer with the current cursor values,
- e.g. with an id of 999, and then del() is called to actually
- delete the record from the database. Remember: all edit operations
- (insert(), update() and delete()) operate on the contents of the
- cursor edit buffer and not on the contents of the cursor itself.
- \sa primeDelete() setMode() lastError()
- */
- int Q3SqlCursor::del(bool invalidate)
- {
- QSqlIndex idx = primaryIndex(false);
- if (idx.isEmpty())
- return del(qWhereClause(&d->editBuffer, d->nm, QLatin1String("and"), driver()), invalidate);
- return del(toString(primaryIndex(), &d->editBuffer, d->nm, QString(QLatin1Char('=')), QLatin1String("and")), invalidate);
- }
- /*!
- \overload
- Deletes the current cursor record from the database using the
- filter \a filter. Only records which meet the filter criteria are
- deleted. Returns the number of records which were deleted. If \a
- invalidate is true (the default), the current cursor can no longer
- be navigated. A new select() call must be made before you can move
- to a valid record. For error information, use lastError().
- The \a filter is an SQL \c WHERE clause, e.g. \c{id=500}.
- \sa setMode() lastError()
- */
- int Q3SqlCursor::del(const QString & filter, bool invalidate)
- {
- if ((d->md & Delete) != Delete)
- return 0;
- int k = count();
- if(k == 0) return 0;
- QString str = QLatin1String("delete from ") + name();
- if (filter.length())
- str+= QLatin1String(" where ") + filter;
- return apply(str, invalidate);
- }
- /*
- \internal
- */
- int Q3SqlCursor::apply(const QString& q, bool invalidate)
- {
- int ar = 0;
- if (invalidate) {
- if (exec(q))
- ar = numRowsAffected();
- } else if (driver()) {
- QSqlQuery* sql = d->query();
- if (sql && sql->exec(q))
- ar = sql->numRowsAffected();
- }
- return ar;
- }
- /*
- \internal
- */
- int Q3SqlCursor::applyPrepared(const QString& q, bool invalidate)
- {
- int ar = 0;
- QSqlQuery* sql = 0;
- if (invalidate) {
- sql = (QSqlQuery*)this;
- d->lastAt = QSql::BeforeFirst;
- } else {
- sql = d->query();
- }
- if (!sql)
- return 0;
- if (invalidate || sql->lastQuery() != q) {
- if (!sql->prepare(q))
- return 0;
- }
- int cnt = 0;
- int fieldCount = (int)count();
- for (int j = 0; j < fieldCount; ++j) {
- const QSqlField f = d->editBuffer.field(j);
- if (d->editBuffer.isGenerated(j)) {
- if (f.type() == QVariant::ByteArray)
- sql->bindValue(cnt, f.value(), QSql::In | QSql::Binary);
- else
- sql->bindValue(cnt, f.value());
- cnt++;
- }
- }
- if (sql->exec()) {
- ar = sql->numRowsAffected();
- }
- return ar;
- }
- /*!
- Executes the SQL query \a sql. Returns true of the cursor is
- active, otherwise returns false.
- */
- bool Q3SqlCursor::exec(const QString & sql)
- {
- d->lastAt = QSql::BeforeFirst;
- QSqlQuery::exec(sql);
- return isActive();
- }
- /*!
- Protected virtual function which is called whenever a field needs
- to be calculated. If calculated fields are being used, derived
- classes must reimplement this function and return the appropriate
- value for field \a name. The default implementation returns an
- invalid QVariant.
- \sa setCalculated()
- */
- QVariant Q3SqlCursor::calculateField(const QString&)
- {
- return QVariant();
- }
- /*! \internal
- Ensure fieldlist is synced with query.
- */
- static QString qTrim(const QString& s)
- {
- QString result = s;
- int end = result.length() - 1;
- while (end >= 0 && result[end].isSpace()) // skip white space from end
- end--;
- result.truncate(end + 1);
- return result;
- }
- /*! \internal
- */
- void Q3SqlCursor::sync()
- {
- if (isActive() && isValid() && d->lastAt != at()) {
- d->lastAt = at();
- int i = 0;
- int j = 0;
- bool haveCalculatedFields = false;
- for (; i < count(); ++i) {
- if (!haveCalculatedFields && d->infoBuffer[i].isCalculated()) {
- haveCalculatedFields = true;
- }
- if (QSqlRecord::isGenerated(i)) {
- QVariant v = QSqlQuery::value(j);
- if ((v.type() == QVariant::String) &&
- d->infoBuffer[i].isTrim()) {
- v = qTrim(v.toString());
- }
- QSqlRecord::setValue(i, v);
- if (QSqlQuery::isNull(j))
- QSqlRecord::field(i).clear();
- j++;
- }
- }
- if (haveCalculatedFields) {
- for (i = 0; i < count(); ++i) {
- if (d->infoBuffer[i].isCalculated())
- QSqlRecord::setValue(i, calculateField(fieldName(i)));
- }
- }
- }
- }
- /*!
- Returns the value of field number \a i.
- */
- QVariant Q3SqlCursor::value(int i) const
- {
- const_cast<Q3SqlCursor *>(this)->sync();
- return QSqlRecord::value(i);
- }
- /*! \internal
- cursors should be filled with Q3SqlFieldInfos...
- */
- void Q3SqlCursor::append(const QSqlField& field)
- {
- append(Q3SqlFieldInfo(field));
- }
- /*!
- Returns true if the field \a i is NULL or if there is no field at
- position \a i; otherwise returns false.
- This is the same as calling QSqlRecord::isNull(\a i)
- */
- bool Q3SqlCursor::isNull(int i) const
- {
- const_cast<Q3SqlCursor *>(this)->sync();
- return QSqlRecord::isNull(i);
- }
- /*!
- \overload
- Returns true if the field called \a name is NULL or if there is no
- field called \a name; otherwise returns false.
- This is the same as calling QSqlRecord::isNull(\a name)
- */
- bool Q3SqlCursor::isNull(const QString& name) const
- {
- const_cast<Q3SqlCursor *>(this)->sync();
- return QSqlRecord::isNull(name);
- }
- /*! \internal */
- void Q3SqlCursor::setValue(int i, const QVariant& val)
- {
- sync();
- #ifdef QT_DEBUG
- qDebug("Q3SqlCursor::setValue(): This will not affect actual database values. Use primeInsert(), primeUpdate() or primeDelete().");
- #endif
- QSqlRecord::setValue(i, val);
- }
- /*! \internal */
- bool Q3SqlCursor::seek(int i, bool relative)
- {
- bool res = QSqlQuery::seek(i, relative);
- sync();
- return res;
- }
- /*! \internal */
- bool Q3SqlCursor::next()
- {
- bool res = QSqlQuery::next();
- sync();
- return res;
- }
- /*!
- \fn Q3SqlCursor::previous()
- \internal
- */
- /*! \internal */
- bool Q3SqlCursor::prev()
- {
- bool res = QSqlQuery::previous();
- sync();
- return res;
- }
- /*! \internal */
- bool Q3SqlCursor::first()
- {
- bool res = QSqlQuery::first();
- sync();
- return res;
- }
- /*! \internal */
- bool Q3SqlCursor::last()
- {
- bool res = QSqlQuery::last();
- sync();
- return res;
- }
- QT_END_NAMESPACE
- #endif