src/sql/kernel/qsqlquery.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sql/kernel/qsqlquery.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1224 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, 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.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qsqlquery.h"
+
+//#define QT_DEBUG_SQL
+
+#include "qatomic.h"
+#include "qsqlrecord.h"
+#include "qsqlresult.h"
+#include "qsqldriver.h"
+#include "qsqldatabase.h"
+#include "private/qsqlnulldriver_p.h"
+#include "qvector.h"
+#include "qmap.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSqlQueryPrivate
+{
+public:
+    QSqlQueryPrivate(QSqlResult* result);
+    ~QSqlQueryPrivate();
+    QAtomicInt ref;
+    QSqlResult* sqlResult;
+
+    static QSqlQueryPrivate* shared_null();
+};
+
+Q_GLOBAL_STATIC_WITH_ARGS(QSqlQueryPrivate, nullQueryPrivate, (0))
+Q_GLOBAL_STATIC(QSqlNullDriver, nullDriver)
+Q_GLOBAL_STATIC_WITH_ARGS(QSqlNullResult, nullResult, (nullDriver()))
+
+QSqlQueryPrivate* QSqlQueryPrivate::shared_null()
+{
+    QSqlQueryPrivate *null = nullQueryPrivate();
+    null->ref.ref();
+    return null;
+}
+
+/*!
+\internal
+*/
+QSqlQueryPrivate::QSqlQueryPrivate(QSqlResult* result)
+    : ref(1), sqlResult(result)
+{
+    if (!sqlResult)
+        sqlResult = nullResult();
+}
+
+QSqlQueryPrivate::~QSqlQueryPrivate()
+{
+    QSqlResult *nr = nullResult();
+    if (!nr || sqlResult == nr)
+        return;
+    delete sqlResult;
+}
+
+/*!
+    \class QSqlQuery
+    \brief The QSqlQuery class provides a means of executing and
+    manipulating SQL statements.
+
+    \ingroup database
+    \ingroup shared
+
+    \inmodule QtSql
+
+    QSqlQuery encapsulates the functionality involved in creating,
+    navigating and retrieving data from SQL queries which are
+    executed on a \l QSqlDatabase. It can be used to execute DML
+    (data manipulation language) statements, such as \c SELECT, \c
+    INSERT, \c UPDATE and \c DELETE, as well as DDL (data definition
+    language) statements, such as \c{CREATE} \c{TABLE}. It can also
+    be used to execute database-specific commands which are not
+    standard SQL (e.g. \c{SET DATESTYLE=ISO} for PostgreSQL).
+
+    Successfully executed SQL statements set the query's state to
+    active so that isActive() returns true. Otherwise the query's
+    state is set to inactive. In either case, when executing a new SQL
+    statement, the query is positioned on an invalid record. An active
+    query must be navigated to a valid record (so that isValid()
+    returns true) before values can be retrieved.
+
+    For some databases, if an active query that is a \c{SELECT}
+    statement exists when you call \l{QSqlDatabase::}{commit()} or
+    \l{QSqlDatabase::}{rollback()}, the commit or rollback will
+    fail. See isActive() for details.
+
+    \target QSqlQuery examples
+
+    Navigating records is performed with the following functions:
+
+    \list
+    \o next()
+    \o previous()
+    \o first()
+    \o last()
+    \o seek()
+    \endlist
+
+    These functions allow the programmer to move forward, backward
+    or arbitrarily through the records returned by the query. If you
+    only need to move forward through the results (e.g., by using
+    next()), you can use setForwardOnly(), which will save a
+    significant amount of memory overhead and improve performance on
+    some databases. Once an active query is positioned on a valid
+    record, data can be retrieved using value(). All data is
+    transferred from the SQL backend using QVariants.
+
+    For example:
+
+    \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 7
+
+    To access the data returned by a query, use value(int). Each
+    field in the data returned by a \c SELECT statement is accessed
+    by passing the field's position in the statement, starting from
+    0. This makes using \c{SELECT *} queries inadvisable because the
+    order of the fields returned is indeterminate.
+
+    For the sake of efficiency, there are no functions to access a
+    field by name (unless you use prepared queries with names, as
+    explained below). To convert a field name into an index, use
+    record().\l{QSqlRecord::indexOf()}{indexOf()}, for example:
+
+    \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 8
+
+    QSqlQuery supports prepared query execution and the binding of
+    parameter values to placeholders. Some databases don't support
+    these features, so for those, Qt emulates the required
+    functionality. For example, the Oracle and ODBC drivers have
+    proper prepared query support, and Qt makes use of it; but for
+    databases that don't have this support, Qt implements the feature
+    itself, e.g. by replacing placeholders with actual values when a
+    query is executed. Use numRowsAffected() to find out how many rows
+    were affected by a non-\c SELECT query, and size() to find how
+    many were retrieved by a \c SELECT.
+
+    Oracle databases identify placeholders by using a colon-name
+    syntax, e.g \c{:name}. ODBC simply uses \c ? characters. Qt
+    supports both syntaxes, with the restriction that you can't mix
+    them in the same query.
+
+    You can retrieve the values of all the fields in a single variable
+    (a map) using boundValues().
+
+    \section1 Approaches to Binding Values
+
+    Below we present the same example using each of the four
+    different binding approaches, as well as one example of binding
+    values to a stored procedure.
+
+    \bold{Named binding using named placeholders:}
+
+    \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 9
+
+    \bold{Positional binding using named placeholders:}
+
+    \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 10
+
+    \bold{Binding values using positional placeholders (version 1):}
+
+    \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 11
+
+    \bold{Binding values using positional placeholders (version 2):}
+
+    \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 12
+
+    \bold{Binding values to a stored procedure:}
+
+    This code calls a stored procedure called \c AsciiToInt(), passing
+    it a character through its in parameter, and taking its result in
+    the out parameter.
+
+    \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 13
+
+    Note that unbound parameters will retain their values.
+
+    Stored procedures that uses the return statement to return values,
+    or return multiple result sets, are not fully supported. For specific
+    details see \l{SQL Database Drivers}.
+
+    \warning You must load the SQL driver and open the connection before a
+    QSqlQuery is created. Also, the connection must remain open while the
+    query exists; otherwise, the behavior of QSqlQuery is undefined.
+
+    \sa QSqlDatabase, QSqlQueryModel, QSqlTableModel, QVariant
+*/
+
+/*!
+    Constructs a QSqlQuery object which uses the QSqlResult \a result
+    to communicate with a database.
+*/
+
+QSqlQuery::QSqlQuery(QSqlResult *result)
+{
+    d = new QSqlQueryPrivate(result);
+}
+
+/*!
+    Destroys the object and frees any allocated resources.
+*/
+
+QSqlQuery::~QSqlQuery()
+{
+    if (!d->ref.deref())
+        delete d;
+}
+
+/*!
+    Constructs a copy of \a other.
+*/
+
+QSqlQuery::QSqlQuery(const QSqlQuery& other)
+{
+    d = other.d;
+    d->ref.ref();
+}
+
+/*!
+    \internal
+*/
+static void qInit(QSqlQuery *q, const QString& query, QSqlDatabase db)
+{
+    QSqlDatabase database = db;
+    if (!database.isValid())
+        database = QSqlDatabase::database(QLatin1String(QSqlDatabase::defaultConnection), false);
+    if (database.isValid()) {
+        *q = QSqlQuery(database.driver()->createResult());
+    }
+    if (!query.isEmpty())
+        q->exec(query);
+}
+
+/*!
+    Constructs a QSqlQuery object using the SQL \a query and the
+    database \a db. If \a db is not specified, the application's
+    default database is used. If \a query is not an empty string, it
+    will be executed.
+
+    \sa QSqlDatabase
+*/
+QSqlQuery::QSqlQuery(const QString& query, QSqlDatabase db)
+{
+    d = QSqlQueryPrivate::shared_null();
+    qInit(this, query, db);
+}
+
+/*!
+    Constructs a QSqlQuery object using the database \a db.
+
+    \sa QSqlDatabase
+*/
+
+QSqlQuery::QSqlQuery(QSqlDatabase db)
+{
+    d = QSqlQueryPrivate::shared_null();
+    qInit(this, QString(), db);
+}
+
+
+/*!
+    Assigns \a other to this object.
+*/
+
+QSqlQuery& QSqlQuery::operator=(const QSqlQuery& other)
+{
+    qAtomicAssign(d, other.d);
+    return *this;
+}
+
+/*!
+  Returns true if the query is \l{isActive()}{active} and positioned
+  on a valid record and the \a field is NULL; otherwise returns
+  false. Note that for some drivers, isNull() will not return accurate
+  information until after an attempt is made to retrieve data.
+
+  \sa isActive(), isValid(), value()
+*/
+
+bool QSqlQuery::isNull(int field) const
+{
+    if (d->sqlResult->isActive() && d->sqlResult->isValid())
+        return d->sqlResult->isNull(field);
+    return true;
+}
+
+/*!
+  
+  Executes the SQL in \a query. Returns true and sets the query state
+  to \l{isActive()}{active} if the query was successful; otherwise
+  returns false. The \a query string must use syntax appropriate for
+  the SQL database being queried (for example, standard SQL).
+
+  After the query is executed, the query is positioned on an \e
+  invalid record and must be navigated to a valid record before data
+  values can be retrieved (for example, using next()).
+
+  Note that the last error for this query is reset when exec() is
+  called.
+
+  Example:
+
+  \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 34
+
+  \sa isActive(), isValid(), next(), previous(), first(), last(),
+  seek()
+*/
+
+bool QSqlQuery::exec(const QString& query)
+{
+    if (d->ref != 1) {
+        bool fo = isForwardOnly();
+        *this = QSqlQuery(driver()->createResult());
+        d->sqlResult->setNumericalPrecisionPolicy(d->sqlResult->numericalPrecisionPolicy());
+        setForwardOnly(fo);
+    } else {
+        d->sqlResult->clear();
+        d->sqlResult->setActive(false);
+        d->sqlResult->setLastError(QSqlError());
+        d->sqlResult->setAt(QSql::BeforeFirstRow);
+        d->sqlResult->setNumericalPrecisionPolicy(d->sqlResult->numericalPrecisionPolicy());
+    }
+    d->sqlResult->setQuery(query.trimmed());
+    if (!driver()->isOpen() || driver()->isOpenError()) {
+        qWarning("QSqlQuery::exec: database not open");
+        return false;
+    }
+    if (query.isEmpty()) {
+        qWarning("QSqlQuery::exec: empty query");
+        return false;
+    }
+#ifdef QT_DEBUG_SQL
+    qDebug("\n QSqlQuery: %s", query.toLocal8Bit().constData());
+#endif
+    return d->sqlResult->reset(query);
+}
+
+/*!
+    Returns the value of field \a index in the current record.
+
+    The fields are numbered from left to right using the text of the
+    \c SELECT statement, e.g. in
+
+    \snippet doc/src/snippets/code/src_sql_kernel_qsqlquery.cpp 0
+
+    field 0 is \c forename and field 1 is \c
+    surname. Using \c{SELECT *} is not recommended because the order
+    of the fields in the query is undefined.
+
+    An invalid QVariant is returned if field \a index does not
+    exist, if the query is inactive, or if the query is positioned on
+    an invalid record.
+
+    \sa previous() next() first() last() seek() isActive() isValid()
+*/
+
+QVariant QSqlQuery::value(int index) const
+{
+    if (isActive() && isValid() && (index > QSql::BeforeFirstRow))
+        return d->sqlResult->data(index);
+    qWarning("QSqlQuery::value: not positioned on a valid record");
+    return QVariant();
+}
+
+/*!
+    Returns the current internal position of the query. The first
+    record is at position zero. If the position is invalid, the
+    function returns QSql::BeforeFirstRow or
+    QSql::AfterLastRow, which are special negative values.
+
+    \sa previous() next() first() last() seek() isActive() isValid()
+*/
+
+int QSqlQuery::at() const
+{
+    return d->sqlResult->at();
+}
+
+/*!
+    Returns the text of the current query being used, or an empty
+    string if there is no current query text.
+
+    \sa executedQuery()
+*/
+
+QString QSqlQuery::lastQuery() const
+{
+    return d->sqlResult->lastQuery();
+}
+
+/*!
+    Returns the database driver associated with the query.
+*/
+
+const QSqlDriver *QSqlQuery::driver() const
+{
+    return d->sqlResult->driver();
+}
+
+/*!
+    Returns the result associated with the query.
+*/
+
+const QSqlResult* QSqlQuery::result() const
+{
+    return d->sqlResult;
+}
+
+/*!
+  Retrieves the record at position \a index, if available, and
+  positions the query on the retrieved record. The first record is at
+  position 0. Note that the query must be in an \l{isActive()}
+  {active} state and isSelect() must return true before calling this
+  function.
+
+  If \a relative is false (the default), the following rules apply:
+
+  \list
+
+  \o If \a index is negative, the result is positioned before the
+  first record and false is returned.
+
+  \o Otherwise, an attempt is made to move to the record at position
+  \a index. If the record at position \a index could not be retrieved,
+  the result is positioned after the last record and false is
+  returned. If the record is successfully retrieved, true is returned.
+
+  \endlist
+
+  If \a relative is true, the following rules apply:
+
+  \list
+
+  \o If the result is currently positioned before the first record or
+  on the first record, and \a index is negative, there is no change,
+  and false is returned.
+
+  \o If the result is currently located after the last record, and \a
+  index is positive, there is no change, and false is returned.
+
+  \o If the result is currently located somewhere in the middle, and
+  the relative offset \a index moves the result below zero, the result
+  is positioned before the first record and false is returned.
+
+  \o Otherwise, an attempt is made to move to the record \a index
+  records ahead of the current record (or \a index records behind the
+  current record if \a index is negative). If the record at offset \a
+  index could not be retrieved, the result is positioned after the
+  last record if \a index >= 0, (or before the first record if \a
+  index is negative), and false is returned. If the record is
+  successfully retrieved, true is returned.
+
+  \endlist
+
+  \sa next() previous() first() last() at() isActive() isValid()
+*/
+bool QSqlQuery::seek(int index, bool relative)
+{
+    if (!isSelect() || !isActive())
+        return false;
+    int actualIdx;
+    if (!relative) { // arbitrary seek
+        if (index < 0) {
+            d->sqlResult->setAt(QSql::BeforeFirstRow);
+            return false;
+        }
+        actualIdx = index;
+    } else {
+        switch (at()) { // relative seek
+        case QSql::BeforeFirstRow:
+            if (index > 0)
+                actualIdx = index;
+            else {
+                return false;
+            }
+            break;
+        case QSql::AfterLastRow:
+            if (index < 0) {
+                d->sqlResult->fetchLast();
+                actualIdx = at() + index;
+            } else {
+                return false;
+            }
+            break;
+        default:
+            if ((at() + index) < 0) {
+                d->sqlResult->setAt(QSql::BeforeFirstRow);
+                return false;
+            }
+            actualIdx = at() + index;
+            break;
+        }
+    }
+    // let drivers optimize
+    if (isForwardOnly() && actualIdx < at()) {
+        qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query");
+        return false;
+    }
+    if (actualIdx == (at() + 1) && at() != QSql::BeforeFirstRow) {
+        if (!d->sqlResult->fetchNext()) {
+            d->sqlResult->setAt(QSql::AfterLastRow);
+            return false;
+        }
+        return true;
+    }
+    if (actualIdx == (at() - 1)) {
+        if (!d->sqlResult->fetchPrevious()) {
+            d->sqlResult->setAt(QSql::BeforeFirstRow);
+            return false;
+        }
+        return true;
+    }
+    if (!d->sqlResult->fetch(actualIdx)) {
+        d->sqlResult->setAt(QSql::AfterLastRow);
+        return false;
+    }
+    return true;
+}
+
+/*!
+  
+  Retrieves the next record in the result, if available, and positions
+  the query on the retrieved record. Note that the result must be in
+  the \l{isActive()}{active} state and isSelect() must return true
+  before calling this function or it will do nothing and return false.
+
+  The following rules apply:
+
+  \list
+
+  \o If the result is currently located before the first record,
+  e.g. immediately after a query is executed, an attempt is made to
+  retrieve the first record.
+
+  \o If the result is currently located after the last record, there
+  is no change and false is returned.
+
+  \o If the result is located somewhere in the middle, an attempt is
+  made to retrieve the next record.
+
+  \endlist
+
+  If the record could not be retrieved, the result is positioned after
+  the last record and false is returned. If the record is successfully
+  retrieved, true is returned.
+
+  \sa previous() first() last() seek() at() isActive() isValid()
+*/
+bool QSqlQuery::next()
+{
+    if (!isSelect() || !isActive())
+        return false;
+    bool b = false;
+    switch (at()) {
+    case QSql::BeforeFirstRow:
+        b = d->sqlResult->fetchFirst();
+        return b;
+    case QSql::AfterLastRow:
+        return false;
+    default:
+        if (!d->sqlResult->fetchNext()) {
+            d->sqlResult->setAt(QSql::AfterLastRow);
+            return false;
+        }
+        return true;
+    }
+}
+
+/*!
+
+  Retrieves the previous record in the result, if available, and
+  positions the query on the retrieved record. Note that the result
+  must be in the \l{isActive()}{active} state and isSelect() must
+  return true before calling this function or it will do nothing and
+  return false.
+
+  The following rules apply:
+
+  \list
+
+  \o If the result is currently located before the first record, there
+  is no change and false is returned.
+
+  \o If the result is currently located after the last record, an
+  attempt is made to retrieve the last record.
+
+  \o If the result is somewhere in the middle, an attempt is made to
+  retrieve the previous record.
+
+  \endlist
+
+  If the record could not be retrieved, the result is positioned
+  before the first record and false is returned. If the record is
+  successfully retrieved, true is returned.
+
+  \sa next() first() last() seek() at() isActive() isValid()
+*/
+bool QSqlQuery::previous()
+{
+    if (!isSelect() || !isActive())
+        return false;
+    if (isForwardOnly()) {
+        qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query");
+        return false;
+    }
+
+    bool b = false;
+    switch (at()) {
+    case QSql::BeforeFirstRow:
+        return false;
+    case QSql::AfterLastRow:
+        b = d->sqlResult->fetchLast();
+        return b;
+    default:
+        if (!d->sqlResult->fetchPrevious()) {
+            d->sqlResult->setAt(QSql::BeforeFirstRow);
+            return false;
+        }
+        return true;
+    }
+}
+
+/*!
+  Retrieves the first record in the result, if available, and
+  positions the query on the retrieved record. Note that the result
+  must be in the \l{isActive()}{active} state and isSelect() must
+  return true before calling this function or it will do nothing and
+  return false.  Returns true if successful. If unsuccessful the query
+  position is set to an invalid position and false is returned.
+
+  \sa next() previous() last() seek() at() isActive() isValid()
+ */
+bool QSqlQuery::first()
+{
+    if (!isSelect() || !isActive())
+        return false;
+    if (isForwardOnly() && at() > QSql::BeforeFirstRow) {
+        qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query");
+        return false;
+    }
+    bool b = false;
+    b = d->sqlResult->fetchFirst();
+    return b;
+}
+
+/*!
+
+  Retrieves the last record in the result, if available, and positions
+  the query on the retrieved record. Note that the result must be in
+  the \l{isActive()}{active} state and isSelect() must return true
+  before calling this function or it will do nothing and return false.
+  Returns true if successful. If unsuccessful the query position is
+  set to an invalid position and false is returned.
+
+  \sa next() previous() first() seek() at() isActive() isValid()
+*/
+
+bool QSqlQuery::last()
+{
+    if (!isSelect() || !isActive())
+        return false;
+    bool b = false;
+    b = d->sqlResult->fetchLast();
+    return b;
+}
+
+/*!
+  Returns the size of the result (number of rows returned), or -1 if
+  the size cannot be determined or if the database does not support
+  reporting information about query sizes. Note that for non-\c SELECT
+  statements (isSelect() returns false), size() will return -1. If the
+  query is not active (isActive() returns false), -1 is returned.
+
+  To determine the number of rows affected by a non-\c SELECT
+  statement, use numRowsAffected().
+
+  \sa isActive() numRowsAffected() QSqlDriver::hasFeature()
+*/
+int QSqlQuery::size() const
+{
+    if (isActive() && d->sqlResult->driver()->hasFeature(QSqlDriver::QuerySize))
+        return d->sqlResult->size();
+    return -1;
+}
+
+/*!
+  Returns the number of rows affected by the result's SQL statement,
+  or -1 if it cannot be determined. Note that for \c SELECT
+  statements, the value is undefined; use size() instead. If the query
+  is not \l{isActive()}{active}, -1 is returned.
+
+  \sa size() QSqlDriver::hasFeature()
+*/
+
+int QSqlQuery::numRowsAffected() const
+{
+    if (isActive())
+        return d->sqlResult->numRowsAffected();
+    return -1;
+}
+
+/*!
+  Returns error information about the last error (if any) that
+  occurred with this query.
+
+  \sa QSqlError, QSqlDatabase::lastError()
+*/
+
+QSqlError QSqlQuery::lastError() const
+{
+    return d->sqlResult->lastError();
+}
+
+/*!
+  Returns true if the query is currently positioned on a valid
+  record; otherwise returns false.
+*/
+
+bool QSqlQuery::isValid() const
+{
+    return d->sqlResult->isValid();
+}
+
+/*!
+  
+  Returns true if the query is \e{active}. An active QSqlQuery is one
+  that has been \l{QSqlQuery::exec()} {exec()'d} successfully but not
+  yet finished with.  When you are finished with an active query, you
+  can make make the query inactive by calling finish() or clear(), or
+  you can delete the QSqlQuery instance.
+
+  \note Of particular interest is an active query that is a \c{SELECT}
+  statement. For some databases that support transactions, an active
+  query that is a \c{SELECT} statement can cause a \l{QSqlDatabase::}
+  {commit()} or a \l{QSqlDatabase::} {rollback()} to fail, so before
+  committing or rolling back, you should make your active \c{SELECT}
+  statement query inactive using one of the ways listed above.
+
+  \sa isSelect()
+ */
+bool QSqlQuery::isActive() const
+{
+    return d->sqlResult->isActive();
+}
+
+/*!
+  Returns true if the current query is a \c SELECT statement;
+  otherwise returns false.
+*/
+
+bool QSqlQuery::isSelect() const
+{
+    return d->sqlResult->isSelect();
+}
+
+/*!
+  Returns true if you can only scroll forward through a result set;
+  otherwise returns false.
+
+  \sa setForwardOnly(), next()
+*/
+bool QSqlQuery::isForwardOnly() const
+{
+    return d->sqlResult->isForwardOnly();
+}
+
+/*!
+  Sets forward only mode to \a forward. If \a forward is true, only
+  next() and seek() with positive values, are allowed for navigating
+  the results.
+
+  Forward only mode can be (depending on the driver) more memory
+  efficient since results do not need to be cached. It will also
+  improve performance on some databases. For this to be true, you must
+  call \c setForwardOnly() before the query is prepared or executed.
+  Note that the constructor that takes a query and a database may
+  execute the query.
+
+  Forward only mode is off by default.
+
+  Setting forward only to false is a suggestion to the database engine,
+  which has the final say on whether a result set is forward only or
+  scrollable. isForwardOnly() will always return the correct status of
+  the result set.
+
+  \sa isForwardOnly(), next(), seek(), QSqlResult::setForwardOnly()
+*/
+void QSqlQuery::setForwardOnly(bool forward)
+{
+    d->sqlResult->setForwardOnly(forward);
+}
+
+/*!
+  Returns a QSqlRecord containing the field information for the
+  current query. If the query points to a valid row (isValid() returns
+  true), the record is populated with the row's values.  An empty
+  record is returned when there is no active query (isActive() returns
+  false).
+
+  To retrieve values from a query, value() should be used since
+  its index-based lookup is faster.
+
+  In the following example, a \c{SELECT * FROM} query is executed.
+  Since the order of the columns is not defined, QSqlRecord::indexOf()
+  is used to obtain the index of a column.
+
+  \snippet doc/src/snippets/code/src_sql_kernel_qsqlquery.cpp 1
+
+  \sa value()
+*/
+QSqlRecord QSqlQuery::record() const
+{
+    QSqlRecord rec = d->sqlResult->record();
+
+    if (isValid()) {
+        for (int i = 0; i < rec.count(); ++i)
+            rec.setValue(i, value(i));
+    }
+    return rec;
+}
+
+/*!
+  Clears the result set and releases any resources held by the
+  query. Sets the query state to inactive. You should rarely if ever
+  need to call this function.
+*/
+void QSqlQuery::clear()
+{
+    *this = QSqlQuery(driver()->createResult());
+}
+
+/*!
+  Prepares the SQL query \a query for execution. Returns true if the
+  query is prepared successfully; otherwise returns false.
+
+  The query may contain placeholders for binding values. Both Oracle
+  style colon-name (e.g., \c{:surname}), and ODBC style (\c{?})
+  placeholders are supported; but they cannot be mixed in the same
+  query. See the \l{QSqlQuery examples}{Detailed Description} for
+  examples.
+
+  Portability note: Some databases choose to delay preparing a query
+  until it is executed the first time. In this case, preparing a
+  syntactically wrong query succeeds, but every consecutive exec()
+  will fail.
+
+  Example:
+
+  \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 9
+
+  \sa exec(), bindValue(), addBindValue()
+*/
+bool QSqlQuery::prepare(const QString& query)
+{
+    if (d->ref != 1) {
+        bool fo = isForwardOnly();
+        *this = QSqlQuery(driver()->createResult());
+        setForwardOnly(fo);
+        d->sqlResult->setNumericalPrecisionPolicy(d->sqlResult->numericalPrecisionPolicy());
+    } else {
+        d->sqlResult->setActive(false);
+        d->sqlResult->setLastError(QSqlError());
+        d->sqlResult->setAt(QSql::BeforeFirstRow);
+        d->sqlResult->setNumericalPrecisionPolicy(d->sqlResult->numericalPrecisionPolicy());
+    }
+    if (!driver()) {
+        qWarning("QSqlQuery::prepare: no driver");
+        return false;
+    }
+    if (!driver()->isOpen() || driver()->isOpenError()) {
+        qWarning("QSqlQuery::prepare: database not open");
+        return false;
+    }
+    if (query.isEmpty()) {
+        qWarning("QSqlQuery::prepare: empty query");
+        return false;
+    }
+#ifdef QT_DEBUG_SQL
+    qDebug("\n QSqlQuery::prepare: %s", query.toLocal8Bit().constData());
+#endif
+    return d->sqlResult->savePrepare(query);
+}
+
+/*!
+  Executes a previously prepared SQL query. Returns true if the query
+  executed successfully; otherwise returns false.
+
+  Note that the last error for this query is reset when exec() is
+  called.
+
+  \sa prepare() bindValue() addBindValue() boundValue() boundValues()
+*/
+bool QSqlQuery::exec()
+{
+    d->sqlResult->resetBindCount();
+
+    if (d->sqlResult->lastError().isValid())
+        d->sqlResult->setLastError(QSqlError());
+
+    return d->sqlResult->exec();
+}
+
+/*! \enum QSqlQuery::BatchExecutionMode
+
+    \value ValuesAsRows - Updates multiple rows. Treats every entry in a QVariantList as a value for updating the next row.
+    \value ValuesAsColumns - Updates a single row. Treats every entry in a QVariantList as a single value of an array type.
+*/
+
+/*!
+    \since 4.2
+
+  Executes a previously prepared SQL query in a batch. All the bound
+  parameters have to be lists of variants. If the database doesn't
+  support batch executions, the driver will simulate it using
+  conventional exec() calls.
+
+  Returns true if the query is executed successfully; otherwise
+  returns false.
+
+  Example:
+
+  \snippet doc/src/snippets/code/src_sql_kernel_qsqlquery.cpp 2
+
+  The example above inserts four new rows into \c myTable:
+
+  \snippet doc/src/snippets/code/src_sql_kernel_qsqlquery.cpp 3
+
+  To bind NULL values, a null QVariant of the relevant type has to be
+  added to the bound QVariantList; for example, \c
+  {QVariant(QVariant::String)} should be used if you are using
+  strings.
+
+  \note Every bound QVariantList must contain the same amount of
+  variants.
+
+  \note The type of the QVariants in a list must not change. For
+  example, you cannot mix integer and string variants within a
+  QVariantList.
+
+  The \a mode parameter indicates how the bound QVariantList will be
+  interpreted.  If \a mode is \c ValuesAsRows, every variant within
+  the QVariantList will be interpreted as a value for a new row. \c
+  ValuesAsColumns is a special case for the Oracle driver. In this
+  mode, every entry within a QVariantList will be interpreted as
+  array-value for an IN or OUT value within a stored procedure.  Note
+  that this will only work if the IN or OUT value is a table-type
+  consisting of only one column of a basic type, for example \c{TYPE
+  myType IS TABLE OF VARCHAR(64) INDEX BY BINARY_INTEGER;}
+
+  \sa prepare(), bindValue(), addBindValue()
+*/
+bool QSqlQuery::execBatch(BatchExecutionMode mode)
+{
+    return d->sqlResult->execBatch(mode == ValuesAsColumns);
+}
+
+/*!
+  Set the placeholder \a placeholder to be bound to value \a val in
+  the prepared statement. Note that the placeholder mark (e.g \c{:})
+  must be included when specifying the placeholder name. If \a
+  paramType is QSql::Out or QSql::InOut, the placeholder will be
+  overwritten with data from the database after the exec() call.
+
+  To bind a NULL value, use a null QVariant; for example, use
+  \c {QVariant(QVariant::String)} if you are binding a string.
+
+  \sa addBindValue(), prepare(), exec(), boundValue() boundValues()
+*/
+void QSqlQuery::bindValue(const QString& placeholder, const QVariant& val,
+                          QSql::ParamType paramType
+)
+{
+    d->sqlResult->bindValue(placeholder, val, paramType);
+}
+
+/*!
+  Set the placeholder in position \a pos to be bound to value \a val
+  in the prepared statement. Field numbering starts at 0. If \a
+  paramType is QSql::Out or QSql::InOut, the placeholder will be
+  overwritten with data from the database after the exec() call.
+*/
+void QSqlQuery::bindValue(int pos, const QVariant& val, QSql::ParamType paramType)
+{
+    d->sqlResult->bindValue(pos, val, paramType);
+}
+
+/*!
+  Adds the value \a val to the list of values when using positional
+  value binding. The order of the addBindValue() calls determines
+  which placeholder a value will be bound to in the prepared query.
+  If \a paramType is QSql::Out or QSql::InOut, the placeholder will be
+  overwritten with data from the database after the exec() call.
+
+  To bind a NULL value, use a null QVariant; for example, use \c
+  {QVariant(QVariant::String)} if you are binding a string.
+
+  \sa bindValue(), prepare(), exec(), boundValue() boundValues()
+*/
+void QSqlQuery::addBindValue(const QVariant& val, QSql::ParamType paramType)
+{
+    d->sqlResult->addBindValue(val, paramType);
+}
+
+/*!
+  Returns the value for the \a placeholder.
+
+  \sa boundValues() bindValue() addBindValue()
+*/
+QVariant QSqlQuery::boundValue(const QString& placeholder) const
+{
+    return d->sqlResult->boundValue(placeholder);
+}
+
+/*!
+  Returns the value for the placeholder at position \a pos.
+*/
+QVariant QSqlQuery::boundValue(int pos) const
+{
+    return d->sqlResult->boundValue(pos);
+}
+
+/*!
+  Returns a map of the bound values.
+
+  With named binding, the bound values can be examined in the
+  following ways:
+
+  \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 14
+
+  With positional binding, the code becomes:
+
+  \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 15
+
+  \sa boundValue() bindValue() addBindValue()
+*/
+QMap<QString,QVariant> QSqlQuery::boundValues() const
+{
+    QMap<QString,QVariant> map;
+
+    const QVector<QVariant> values(d->sqlResult->boundValues());
+    for (int i = 0; i < values.count(); ++i)
+        map[d->sqlResult->boundValueName(i)] = values.at(i);
+    return map;
+}
+
+/*!
+  Returns the last query that was successfully executed.
+
+  In most cases this function returns the same string as lastQuery().
+  If a prepared query with placeholders is executed on a DBMS that
+  does not support it, the preparation of this query is emulated. The
+  placeholders in the original query are replaced with their bound
+  values to form a new query. This function returns the modified
+  query. It is mostly useful for debugging purposes.
+
+  \sa lastQuery()
+*/
+QString QSqlQuery::executedQuery() const
+{
+    return d->sqlResult->executedQuery();
+}
+
+/*!
+  \fn bool QSqlQuery::prev()
+
+  Use previous() instead.
+*/
+
+/*!
+  Returns the object ID of the most recent inserted row if the
+  database supports it.  An invalid QVariant will be returned if the
+  query did not insert any value or if the database does not report
+  the id back.  If more than one row was touched by the insert, the
+  behavior is undefined.
+
+  For MySQL databases the row's auto-increment field will be returned.
+    
+  \note For this function to work in PSQL, the table table must
+  contain OIDs, which may not have been created by default.  Check the
+  \c default_with_oids configuration variable to be sure.
+
+  \sa QSqlDriver::hasFeature()
+*/
+QVariant QSqlQuery::lastInsertId() const
+{
+    return d->sqlResult->lastInsertId();
+}
+
+/*!
+
+  Instruct the database driver to return numerical values with a
+  precision specified by \a precisionPolicy.
+
+  The Oracle driver, for example, can retrieve numerical values as
+  strings to prevent the loss of precision. If high precision doesn't
+  matter, use this method to increase execution speed by bypassing
+  string conversions.
+
+  Note: Drivers that don't support fetching numerical values with low
+  precision will ignore the precision policy. You can use
+  QSqlDriver::hasFeature() to find out whether a driver supports this
+  feature.
+
+  Note: Setting the precision policy doesn't affect the currently
+  active query. Call \l{exec()}{exec(QString)} or prepare() in order
+  to activate the policy.
+
+  \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy()
+*/
+void QSqlQuery::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy)
+{
+    d->sqlResult->setNumericalPrecisionPolicy(precisionPolicy);
+}
+
+/*!
+  Returns the current precision policy.
+
+  \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy()
+*/
+QSql::NumericalPrecisionPolicy QSqlQuery::numericalPrecisionPolicy() const
+{
+    return d->sqlResult->numericalPrecisionPolicy();
+}
+
+/*!
+  \since 4.3.2
+
+  Instruct the database driver that no more data will be fetched from
+  this query until it is re-executed. There is normally no need to
+  call this function, but it may be helpful in order to free resources
+  such as locks or cursors if you intend to re-use the query at a
+  later time.
+    
+  Sets the query to inactive. Bound values retain their values.
+
+  \sa prepare() exec() isActive()
+*/
+void QSqlQuery::finish()
+{
+    if (isActive()) {
+        d->sqlResult->setLastError(QSqlError());
+        d->sqlResult->setAt(QSql::BeforeFirstRow);
+        d->sqlResult->detachFromResultSet();
+        d->sqlResult->setActive(false);
+    }
+}
+
+/*!
+  \since 4.4
+ 
+  Discards the current result set and navigates to the next if available.
+
+  Some databases are capable of returning multiple result sets for
+  stored procedures or SQL batches (a query strings that contains
+  multiple statements). If multiple result sets are available after
+  executing a query this function can be used to navigate to the next
+  result set(s).
+    
+  If a new result set is available this function will return true.
+  The query will be repositioned on an \e invalid record in the new
+  result set and must be navigated to a valid record before data
+  values can be retrieved. If a new result set isn't available the
+  function returns false and the query is set to inactive. In any
+  case the old result set will be discarded.
+
+  When one of the statements is a non-select statement a count of
+  affected rows may be available instead of a result set.
+
+  Note that some databases, i.e. Microsoft SQL Server, requires
+  non-scrollable cursors when working with multiple result sets.  Some
+  databases may execute all statements at once while others may delay
+  the execution until the result set is actually accessed, and some
+  databases may have restrictions on which statements are allowed to
+  be used in a SQL batch.
+
+  \sa QSqlDriver::hasFeature() setForwardOnly() next() isSelect() numRowsAffected() isActive() lastError()
+*/
+bool QSqlQuery::nextResult()
+{
+    if (isActive())
+        return d->sqlResult->nextResult();
+    return false;
+}
+
+QT_END_NAMESPACE