summaryrefslogtreecommitdiffstats
path: root/src/sql/kernel
diff options
context:
space:
mode:
authorQt by Nokia <qt-info@nokia.com>2011-04-27 12:05:43 +0200
committeraxis <qt-info@nokia.com>2011-04-27 12:05:43 +0200
commit38be0d13830efd2d98281c645c3a60afe05ffece (patch)
tree6ea73f3ec77f7d153333779883e8120f82820abe /src/sql/kernel
Initial import from the monolithic Qt.
This is the beginning of revision history for this module. If you want to look at revision history older than this, please refer to the Qt Git wiki for how to use Git history grafting. At the time of writing, this wiki is located here: http://qt.gitorious.org/qt/pages/GitIntroductionWithQt If you have already performed the grafting and you don't see any history beyond this commit, try running "git log" with the "--follow" argument. Branched from the monolithic repo, Qt master branch, at commit 896db169ea224deb96c59ce8af800d019de63f12
Diffstat (limited to 'src/sql/kernel')
-rw-r--r--src/sql/kernel/kernel.pri24
-rw-r--r--src/sql/kernel/qsql.h113
-rw-r--r--src/sql/kernel/qsql.qdoc125
-rw-r--r--src/sql/kernel/qsqlcachedresult.cpp318
-rw-r--r--src/sql/kernel/qsqlcachedresult_p.h100
-rw-r--r--src/sql/kernel/qsqldatabase.cpp1547
-rw-r--r--src/sql/kernel/qsqldatabase.h161
-rw-r--r--src/sql/kernel/qsqldriver.cpp948
-rw-r--r--src/sql/kernel/qsqldriver.h160
-rw-r--r--src/sql/kernel/qsqldriverplugin.cpp108
-rw-r--r--src/sql/kernel/qsqldriverplugin.h81
-rw-r--r--src/sql/kernel/qsqlerror.cpp253
-rw-r--r--src/sql/kernel/qsqlerror.h104
-rw-r--r--src/sql/kernel/qsqlfield.cpp560
-rw-r--r--src/sql/kernel/qsqlfield.h119
-rw-r--r--src/sql/kernel/qsqlindex.cpp256
-rw-r--r--src/sql/kernel/qsqlindex.h92
-rw-r--r--src/sql/kernel/qsqlnulldriver_p.h114
-rw-r--r--src/sql/kernel/qsqlquery.cpp1236
-rw-r--r--src/sql/kernel/qsqlquery.h130
-rw-r--r--src/sql/kernel/qsqlrecord.cpp605
-rw-r--r--src/sql/kernel/qsqlrecord.h123
-rw-r--r--src/sql/kernel/qsqlresult.cpp1040
-rw-r--r--src/sql/kernel/qsqlresult.h153
24 files changed, 8470 insertions, 0 deletions
diff --git a/src/sql/kernel/kernel.pri b/src/sql/kernel/kernel.pri
new file mode 100644
index 0000000000..c6fe404737
--- /dev/null
+++ b/src/sql/kernel/kernel.pri
@@ -0,0 +1,24 @@
+HEADERS += kernel/qsql.h \
+ kernel/qsqlquery.h \
+ kernel/qsqldatabase.h \
+ kernel/qsqlfield.h \
+ kernel/qsqlrecord.h \
+ kernel/qsqldriver.h \
+ kernel/qsqlnulldriver_p.h \
+ kernel/qsqldriverplugin.h \
+ kernel/qsqlerror.h \
+ kernel/qsqlresult.h \
+ kernel/qsqlcachedresult_p.h \
+ kernel/qsqlindex.h
+
+SOURCES += kernel/qsqlquery.cpp \
+ kernel/qsqldatabase.cpp \
+ kernel/qsqlfield.cpp \
+ kernel/qsqlrecord.cpp \
+ kernel/qsqldriver.cpp \
+ kernel/qsqldriverplugin.cpp \
+ kernel/qsqlerror.cpp \
+ kernel/qsqlresult.cpp \
+ kernel/qsqlindex.cpp \
+ kernel/qsqlcachedresult.cpp
+
diff --git a/src/sql/kernel/qsql.h b/src/sql/kernel/qsql.h
new file mode 100644
index 0000000000..0cfe3880ed
--- /dev/null
+++ b/src/sql/kernel/qsql.h
@@ -0,0 +1,113 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQL_H
+#define QSQL_H
+
+#include <QtCore/qglobal.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sql)
+
+namespace QSql
+{
+ enum Location
+ {
+ BeforeFirstRow = -1,
+ AfterLastRow = -2
+#ifdef QT3_SUPPORT
+ , BeforeFirst = BeforeFirstRow,
+ AfterLast = AfterLastRow
+#endif
+ };
+
+ enum ParamTypeFlag
+ {
+ In = 0x00000001,
+ Out = 0x00000002,
+ InOut = In | Out,
+ Binary = 0x00000004
+ };
+ Q_DECLARE_FLAGS(ParamType, ParamTypeFlag)
+
+ enum TableType
+ {
+ Tables = 0x01,
+ SystemTables = 0x02,
+ Views = 0x04,
+ AllTables = 0xff
+ };
+
+ enum NumericalPrecisionPolicy
+ {
+ LowPrecisionInt32 = 0x01,
+ LowPrecisionInt64 = 0x02,
+ LowPrecisionDouble = 0x04,
+
+ HighPrecision = 0
+ };
+
+#ifdef QT3_SUPPORT
+ enum Op {
+ None = -1,
+ Insert = 0,
+ Update = 1,
+ Delete = 2
+ };
+
+ enum Confirm {
+ Cancel = -1,
+ No = 0,
+ Yes = 1
+ };
+#endif
+}
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QSql::ParamType)
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSQL_H
diff --git a/src/sql/kernel/qsql.qdoc b/src/sql/kernel/qsql.qdoc
new file mode 100644
index 0000000000..3a2cf245a0
--- /dev/null
+++ b/src/sql/kernel/qsql.qdoc
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the documentation of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:FDL$
+** 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 Free Documentation License
+** Alternatively, this file may be used under the terms of the GNU Free
+** Documentation License version 1.3 as published by the Free Software
+** Foundation and appearing in the file included in the packaging of this
+** file.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+/*!
+ \namespace QSql
+ \inmodule QtSql
+ \brief The QSql namespace contains miscellaneous identifiers used throughout
+ the Qt SQL library.
+
+ \inheaderfile QtSql
+ \ingroup database
+
+
+ \sa {QtSql Module}
+*/
+
+/*!
+ \enum QSql::Confirm
+ \compat
+
+ This enum type describes edit confirmations.
+
+ \value Yes
+ \value No
+ \value Cancel
+*/
+
+/*!
+ \enum QSql::Op
+ \compat
+
+ This enum type describes edit operations.
+
+ \value None
+ \value Insert
+ \value Update
+ \value Delete
+*/
+
+
+/*!
+ \enum QSql::Location
+
+ This enum type describes special SQL navigation locations:
+
+ \value BeforeFirstRow Before the first record.
+ \value AfterLastRow After the last record.
+
+ \omitvalue BeforeFirst
+ \omitvalue AfterLast
+
+ \sa QSqlQuery::at()
+*/
+
+/*!
+ \enum QSql::ParamTypeFlag
+
+ This enum is used to specify the type of a bind parameter.
+
+ \value In The bind parameter is used to put data into the database.
+ \value Out The bind parameter is used to receive data from the database.
+ \value InOut The bind parameter is used to put data into the
+ database; it will be overwritten with output data on executing
+ a query.
+ \value Binary This must be OR'd with one of the other flags if
+ you want to indicate that the data being transferred is
+ raw binary data.
+*/
+
+/*!
+ \enum QSql::TableType
+
+ This enum type describes types of SQL tables.
+
+ \value Tables All the tables visible to the user.
+ \value SystemTables Internal tables used by the database.
+ \value Views All the views visible to the user.
+ \value AllTables All of the above.
+*/
+
+/*!
+ \enum QSql::NumericalPrecisionPolicy
+
+ This enum type describes at which precision levels numercial values are read from
+ a database.
+
+ Some databases support numerical values with a precision that is not storable in a
+ C++ basic data type. The default behavior is to bind these values as a QString.
+ This enum can be used to override this behavior.
+
+ \value LowPrecisionInt32 Force 32bit integer values. In case of floating point numbers,
+ the fractional part is silently discarded.
+ \value LowPrecisionInt64 Force 64bit integer values. In case of floating point numbers,
+ the fractional part is silently discarded.
+ \value LowPrecisionDouble Force \c double values.
+ \value HighPrecision The default behavior - try to preserve maximum precision.
+
+ Note: The actual behaviour if an overflow occurs is driver specific. The Oracle database
+ just returns an error in this case.
+*/
+
diff --git a/src/sql/kernel/qsqlcachedresult.cpp b/src/sql/kernel/qsqlcachedresult.cpp
new file mode 100644
index 0000000000..47ed5bf1f8
--- /dev/null
+++ b/src/sql/kernel/qsqlcachedresult.cpp
@@ -0,0 +1,318 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "private/qsqlcachedresult_p.h"
+
+#include <qvariant.h>
+#include <qdatetime.h>
+#include <qvector.h>
+
+QT_BEGIN_NAMESPACE
+
+/*
+ QSqlCachedResult is a convenience class for databases that only allow
+ forward only fetching. It will cache all the results so we can iterate
+ backwards over the results again.
+
+ All you need to do is to inherit from QSqlCachedResult and reimplement
+ gotoNext(). gotoNext() will have a reference to the internal cache and
+ will give you an index where you can start filling in your data. Special
+ case: If the user actually wants a forward-only query, idx will be -1
+ to indicate that we are not interested in the actual values.
+*/
+
+static const uint initial_cache_size = 128;
+
+class QSqlCachedResultPrivate
+{
+public:
+ QSqlCachedResultPrivate();
+ bool canSeek(int i) const;
+ inline int cacheCount() const;
+ void init(int count, bool fo);
+ void cleanup();
+ int nextIndex();
+ void revertLast();
+
+ QSqlCachedResult::ValueCache cache;
+ int rowCacheEnd;
+ int colCount;
+ bool forwardOnly;
+ bool atEnd;
+};
+
+QSqlCachedResultPrivate::QSqlCachedResultPrivate():
+ rowCacheEnd(0), colCount(0), forwardOnly(false), atEnd(false)
+{
+}
+
+void QSqlCachedResultPrivate::cleanup()
+{
+ cache.clear();
+ forwardOnly = false;
+ atEnd = false;
+ colCount = 0;
+ rowCacheEnd = 0;
+}
+
+void QSqlCachedResultPrivate::init(int count, bool fo)
+{
+ Q_ASSERT(count);
+ cleanup();
+ forwardOnly = fo;
+ colCount = count;
+ if (fo) {
+ cache.resize(count);
+ rowCacheEnd = count;
+ } else {
+ cache.resize(initial_cache_size * count);
+ }
+}
+
+int QSqlCachedResultPrivate::nextIndex()
+{
+ if (forwardOnly)
+ return 0;
+ int newIdx = rowCacheEnd;
+ if (newIdx + colCount > cache.size())
+ cache.resize(qMin(cache.size() * 2, cache.size() + 10000));
+ rowCacheEnd += colCount;
+
+ return newIdx;
+}
+
+bool QSqlCachedResultPrivate::canSeek(int i) const
+{
+ if (forwardOnly || i < 0)
+ return false;
+ return rowCacheEnd >= (i + 1) * colCount;
+}
+
+void QSqlCachedResultPrivate::revertLast()
+{
+ if (forwardOnly)
+ return;
+ rowCacheEnd -= colCount;
+}
+
+inline int QSqlCachedResultPrivate::cacheCount() const
+{
+ Q_ASSERT(!forwardOnly);
+ Q_ASSERT(colCount);
+ return rowCacheEnd / colCount;
+}
+
+//////////////
+
+QSqlCachedResult::QSqlCachedResult(const QSqlDriver * db): QSqlResult (db)
+{
+ d = new QSqlCachedResultPrivate();
+}
+
+QSqlCachedResult::~QSqlCachedResult()
+{
+ delete d;
+}
+
+void QSqlCachedResult::init(int colCount)
+{
+ d->init(colCount, isForwardOnly());
+}
+
+bool QSqlCachedResult::fetch(int i)
+{
+ if ((!isActive()) || (i < 0))
+ return false;
+ if (at() == i)
+ return true;
+ if (d->forwardOnly) {
+ // speed hack - do not copy values if not needed
+ if (at() > i || at() == QSql::AfterLastRow)
+ return false;
+ while(at() < i - 1) {
+ if (!gotoNext(d->cache, -1))
+ return false;
+ setAt(at() + 1);
+ }
+ if (!gotoNext(d->cache, 0))
+ return false;
+ setAt(at() + 1);
+ return true;
+ }
+ if (d->canSeek(i)) {
+ setAt(i);
+ return true;
+ }
+ if (d->rowCacheEnd > 0)
+ setAt(d->cacheCount());
+ while (at() < i + 1) {
+ if (!cacheNext()) {
+ if (d->canSeek(i))
+ break;
+ return false;
+ }
+ }
+ setAt(i);
+
+ return true;
+}
+
+bool QSqlCachedResult::fetchNext()
+{
+ if (d->canSeek(at() + 1)) {
+ setAt(at() + 1);
+ return true;
+ }
+ return cacheNext();
+}
+
+bool QSqlCachedResult::fetchPrevious()
+{
+ return fetch(at() - 1);
+}
+
+bool QSqlCachedResult::fetchFirst()
+{
+ if (d->forwardOnly && at() != QSql::BeforeFirstRow) {
+ return false;
+ }
+ if (d->canSeek(0)) {
+ setAt(0);
+ return true;
+ }
+ return cacheNext();
+}
+
+bool QSqlCachedResult::fetchLast()
+{
+ if (d->atEnd) {
+ if (d->forwardOnly)
+ return false;
+ else
+ return fetch(d->cacheCount() - 1);
+ }
+
+ int i = at();
+ while (fetchNext())
+ ++i; /* brute force */
+ if (d->forwardOnly && at() == QSql::AfterLastRow) {
+ setAt(i);
+ return true;
+ } else {
+ return fetch(i);
+ }
+}
+
+QVariant QSqlCachedResult::data(int i)
+{
+ int idx = d->forwardOnly ? i : at() * d->colCount + i;
+ if (i >= d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd)
+ return QVariant();
+
+ return d->cache.at(idx);
+}
+
+bool QSqlCachedResult::isNull(int i)
+{
+ int idx = d->forwardOnly ? i : at() * d->colCount + i;
+ if (i > d->colCount || i < 0 || at() < 0 || idx >= d->rowCacheEnd)
+ return true;
+
+ return d->cache.at(idx).isNull();
+}
+
+void QSqlCachedResult::cleanup()
+{
+ setAt(QSql::BeforeFirstRow);
+ setActive(false);
+ d->cleanup();
+}
+
+void QSqlCachedResult::clearValues()
+{
+ setAt(QSql::BeforeFirstRow);
+ d->rowCacheEnd = 0;
+ d->atEnd = false;
+}
+
+bool QSqlCachedResult::cacheNext()
+{
+ if (d->atEnd)
+ return false;
+
+ if(isForwardOnly()) {
+ d->cache.clear();
+ d->cache.resize(d->colCount);
+ }
+
+ if (!gotoNext(d->cache, d->nextIndex())) {
+ d->revertLast();
+ d->atEnd = true;
+ return false;
+ }
+ setAt(at() + 1);
+ return true;
+}
+
+int QSqlCachedResult::colCount() const
+{
+ return d->colCount;
+}
+
+QSqlCachedResult::ValueCache &QSqlCachedResult::cache()
+{
+ return d->cache;
+}
+
+void QSqlCachedResult::virtual_hook(int id, void *data)
+{
+ switch (id) {
+ case QSqlResult::DetachFromResultSet:
+ case QSqlResult::SetNumericalPrecision:
+ cleanup();
+ break;
+ default:
+ QSqlResult::virtual_hook(id, data);
+ }
+}
+
+
+QT_END_NAMESPACE
diff --git a/src/sql/kernel/qsqlcachedresult_p.h b/src/sql/kernel/qsqlcachedresult_p.h
new file mode 100644
index 0000000000..a76ca0bbbc
--- /dev/null
+++ b/src/sql/kernel/qsqlcachedresult_p.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQLCACHEDRESULT_P_H
+#define QSQLCACHEDRESULT_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. It exists for the convenience
+// of other Qt classes. This header file may change from version to
+// version without notice, or even be removed.
+//
+// We mean it.
+//
+
+#include "QtSql/qsqlresult.h"
+
+QT_BEGIN_NAMESPACE
+
+class QVariant;
+template <typename T> class QVector;
+
+class QSqlCachedResultPrivate;
+
+class Q_SQL_EXPORT QSqlCachedResult: public QSqlResult
+{
+public:
+ virtual ~QSqlCachedResult();
+
+ typedef QVector<QVariant> ValueCache;
+
+protected:
+ QSqlCachedResult(const QSqlDriver * db);
+
+ void init(int colCount);
+ void cleanup();
+ void clearValues();
+
+ virtual bool gotoNext(ValueCache &values, int index) = 0;
+
+ QVariant data(int i);
+ bool isNull(int i);
+ bool fetch(int i);
+ bool fetchNext();
+ bool fetchPrevious();
+ bool fetchFirst();
+ bool fetchLast();
+
+ int colCount() const;
+ ValueCache &cache();
+
+ void virtual_hook(int id, void *data);
+private:
+ bool cacheNext();
+ QSqlCachedResultPrivate *d;
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQLCACHEDRESULT_P_H
diff --git a/src/sql/kernel/qsqldatabase.cpp b/src/sql/kernel/qsqldatabase.cpp
new file mode 100644
index 0000000000..b0ae8d9ea6
--- /dev/null
+++ b/src/sql/kernel/qsqldatabase.cpp
@@ -0,0 +1,1547 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qsqldatabase.h"
+#include "qsqlquery.h"
+
+#ifdef Q_OS_WIN32
+// Conflicting declarations of LPCBYTE in sqlfront.h and winscard.h
+#define _WINSCARD_H_
+#endif
+
+#ifdef QT_SQL_PSQL
+#include "../drivers/psql/qsql_psql.h"
+#endif
+#ifdef QT_SQL_MYSQL
+#include "../drivers/mysql/qsql_mysql.h"
+#endif
+#ifdef QT_SQL_ODBC
+#include "../drivers/odbc/qsql_odbc.h"
+#endif
+#ifdef QT_SQL_OCI
+#include "../drivers/oci/qsql_oci.h"
+#endif
+#ifdef QT_SQL_TDS
+// conflicting RETCODE typedef between odbc and freetds
+#define RETCODE DBRETCODE
+#include "../drivers/tds/qsql_tds.h"
+#undef RETCODE
+#endif
+#ifdef QT_SQL_DB2
+#include "../drivers/db2/qsql_db2.h"
+#endif
+#ifdef QT_SQL_SQLITE
+#include "../drivers/sqlite/qsql_sqlite.h"
+#endif
+#ifdef QT_SQL_SQLITE2
+#include "../drivers/sqlite2/qsql_sqlite2.h"
+#endif
+#ifdef QT_SQL_IBASE
+#undef SQL_FLOAT // avoid clash with ODBC
+#undef SQL_DOUBLE
+#undef SQL_TIMESTAMP
+#undef SQL_TYPE_TIME
+#undef SQL_TYPE_DATE
+#undef SQL_DATE
+#define SCHAR IBASE_SCHAR // avoid clash with ODBC (older versions of ibase.h with Firebird)
+#include "../drivers/ibase/qsql_ibase.h"
+#undef SCHAR
+#endif
+
+#include "qdebug.h"
+#include "qcoreapplication.h"
+#include "qreadwritelock.h"
+#include "qsqlresult.h"
+#include "qsqldriver.h"
+#include "qsqldriverplugin.h"
+#include "qsqlindex.h"
+#include "private/qfactoryloader_p.h"
+#include "private/qsqlnulldriver_p.h"
+#include "qmutex.h"
+#include "qhash.h"
+#include <stdlib.h>
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_LIBRARY
+Q_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader,
+ (QSqlDriverFactoryInterface_iid,
+ QLatin1String("/sqldrivers")))
+#endif
+
+QT_STATIC_CONST_IMPL char *QSqlDatabase::defaultConnection = "qt_sql_default_connection";
+
+typedef QHash<QString, QSqlDriverCreatorBase*> DriverDict;
+
+class QConnectionDict: public QHash<QString, QSqlDatabase>
+{
+public:
+ inline bool contains_ts(const QString &key)
+ {
+ QReadLocker locker(&lock);
+ return contains(key);
+ }
+ inline QStringList keys_ts() const
+ {
+ QReadLocker locker(&lock);
+ return keys();
+ }
+
+ mutable QReadWriteLock lock;
+};
+Q_GLOBAL_STATIC(QConnectionDict, dbDict)
+
+class QSqlDatabasePrivate
+{
+public:
+ QSqlDatabasePrivate(QSqlDatabase *d, QSqlDriver *dr = 0):
+ q(d),
+ driver(dr),
+ port(-1)
+ {
+ ref = 1;
+ if(driver)
+ precisionPolicy = driver->numericalPrecisionPolicy();
+ else
+ precisionPolicy= QSql::LowPrecisionDouble;
+ }
+ QSqlDatabasePrivate(const QSqlDatabasePrivate &other);
+ ~QSqlDatabasePrivate();
+ void init(const QString& type);
+ void copy(const QSqlDatabasePrivate *other);
+ void disable();
+
+ QAtomicInt ref;
+ QSqlDatabase *q;
+ QSqlDriver* driver;
+ QString dbname;
+ QString uname;
+ QString pword;
+ QString hname;
+ QString drvName;
+ int port;
+ QString connOptions;
+ QString connName;
+ QSql::NumericalPrecisionPolicy precisionPolicy;
+
+ static QSqlDatabasePrivate *shared_null();
+ static QSqlDatabase database(const QString& name, bool open);
+ static void addDatabase(const QSqlDatabase &db, const QString & name);
+ static void removeDatabase(const QString& name);
+ static void invalidateDb(const QSqlDatabase &db, const QString &name, bool doWarn = true);
+ static DriverDict &driverDict();
+ static void cleanConnections();
+};
+
+QSqlDatabasePrivate::QSqlDatabasePrivate(const QSqlDatabasePrivate &other)
+{
+ ref = 1;
+ q = other.q;
+ dbname = other.dbname;
+ uname = other.uname;
+ pword = other.pword;
+ hname = other.hname;
+ drvName = other.drvName;
+ port = other.port;
+ connOptions = other.connOptions;
+ driver = other.driver;
+ precisionPolicy = other.precisionPolicy;
+}
+
+QSqlDatabasePrivate::~QSqlDatabasePrivate()
+{
+ if (driver != shared_null()->driver)
+ delete driver;
+}
+
+void QSqlDatabasePrivate::cleanConnections()
+{
+ QConnectionDict *dict = dbDict();
+ Q_ASSERT(dict);
+ QWriteLocker locker(&dict->lock);
+
+ QConnectionDict::iterator it = dict->begin();
+ while (it != dict->end()) {
+ invalidateDb(it.value(), it.key(), false);
+ ++it;
+ }
+ dict->clear();
+}
+
+static bool qDriverDictInit = false;
+static void cleanDriverDict()
+{
+ qDeleteAll(QSqlDatabasePrivate::driverDict());
+ QSqlDatabasePrivate::driverDict().clear();
+ QSqlDatabasePrivate::cleanConnections();
+ qDriverDictInit = false;
+}
+
+DriverDict &QSqlDatabasePrivate::driverDict()
+{
+ static DriverDict dict;
+ if (!qDriverDictInit) {
+ qDriverDictInit = true;
+ qAddPostRoutine(cleanDriverDict);
+ }
+ return dict;
+}
+
+QSqlDatabasePrivate *QSqlDatabasePrivate::shared_null()
+{
+ static QSqlNullDriver dr;
+ static QSqlDatabasePrivate n(NULL, &dr);
+ return &n;
+}
+
+void QSqlDatabasePrivate::invalidateDb(const QSqlDatabase &db, const QString &name, bool doWarn)
+{
+ if (db.d->ref != 1 && doWarn) {
+ qWarning("QSqlDatabasePrivate::removeDatabase: connection '%s' is still in use, "
+ "all queries will cease to work.", name.toLocal8Bit().constData());
+ db.d->disable();
+ db.d->connName.clear();
+ }
+}
+
+void QSqlDatabasePrivate::removeDatabase(const QString &name)
+{
+ QConnectionDict *dict = dbDict();
+ Q_ASSERT(dict);
+ QWriteLocker locker(&dict->lock);
+
+ if (!dict->contains(name))
+ return;
+
+ invalidateDb(dict->take(name), name);
+}
+
+void QSqlDatabasePrivate::addDatabase(const QSqlDatabase &db, const QString &name)
+{
+ QConnectionDict *dict = dbDict();
+ Q_ASSERT(dict);
+ QWriteLocker locker(&dict->lock);
+
+ if (dict->contains(name)) {
+ invalidateDb(dict->take(name), name);
+ qWarning("QSqlDatabasePrivate::addDatabase: duplicate connection name '%s', old "
+ "connection removed.", name.toLocal8Bit().data());
+ }
+ dict->insert(name, db);
+ db.d->connName = name;
+}
+
+/*! \internal
+*/
+QSqlDatabase QSqlDatabasePrivate::database(const QString& name, bool open)
+{
+ const QConnectionDict *dict = dbDict();
+ Q_ASSERT(dict);
+
+ dict->lock.lockForRead();
+ QSqlDatabase db = dict->value(name);
+ dict->lock.unlock();
+ if (db.isValid() && !db.isOpen() && open) {
+ if (!db.open())
+ qWarning() << "QSqlDatabasePrivate::database: unable to open database:" << db.lastError().text();
+
+ }
+ return db;
+}
+
+
+/*! \internal
+ Copies the connection data from \a other.
+*/
+void QSqlDatabasePrivate::copy(const QSqlDatabasePrivate *other)
+{
+ q = other->q;
+ dbname = other->dbname;
+ uname = other->uname;
+ pword = other->pword;
+ hname = other->hname;
+ drvName = other->drvName;
+ port = other->port;
+ connOptions = other->connOptions;
+ precisionPolicy = other->precisionPolicy;
+}
+
+void QSqlDatabasePrivate::disable()
+{
+ if (driver != shared_null()->driver) {
+ delete driver;
+ driver = shared_null()->driver;
+ }
+}
+
+/*!
+ \class QSqlDriverCreatorBase
+ \brief The QSqlDriverCreatorBase class is the base class for
+ SQL driver factories.
+
+ \ingroup database
+ \inmodule QtSql
+
+ Reimplement createObject() to return an instance of the specific
+ QSqlDriver subclass that you want to provide.
+
+ See QSqlDatabase::registerSqlDriver() for details.
+
+ \sa QSqlDriverCreator
+*/
+
+/*!
+ \fn QSqlDriverCreatorBase::~QSqlDriverCreatorBase()
+
+ Destroys the SQL driver creator object.
+*/
+
+/*!
+ \fn QSqlDriver *QSqlDriverCreatorBase::createObject() const
+
+ Reimplement this function to returns a new instance of a
+ QSqlDriver subclass.
+*/
+
+/*!
+ \class QSqlDriverCreator
+ \brief The QSqlDriverCreator class is a template class that
+ provides a SQL driver factory for a specific driver type.
+
+ \ingroup database
+ \inmodule QtSql
+
+ QSqlDriverCreator<T> instantiates objects of type T, where T is a
+ QSqlDriver subclass.
+
+ See QSqlDatabase::registerSqlDriver() for details.
+*/
+
+/*!
+ \fn QSqlDriver *QSqlDriverCreator::createObject() const
+ \reimp
+*/
+
+/*!
+ \class QSqlDatabase
+ \brief The QSqlDatabase class represents a connection to
+ a database.
+
+ \ingroup database
+
+ \inmodule QtSql
+
+ The QSqlDatabase class provides an interface for accessing a
+ database through a connection. An instance of QSqlDatabase
+ represents the connection. The connection provides access to the
+ database via one of the \l{SQL Database Drivers#Supported
+ Databases} {supported database drivers}, which are derived from
+ QSqlDriver. Alternatively, you can subclass your own database
+ driver from QSqlDriver. See \l{How to Write Your Own Database
+ Driver} for more information.
+
+ Create a connection (i.e., an instance of QSqlDatabase) by calling
+ one of the static addDatabase() functions, where you specify
+ \l{SQL Database Drivers#Supported Databases} {the driver or type
+ of driver} to use (i.e., what kind of database will you access?)
+ and a connection name. A connection is known by its own name,
+ \e{not} by the name of the database it connects to. You can have
+ multiple connections to one database. QSqlDatabase also supports
+ the concept of a \e{default} connection, which is the unnamed
+ connection. To create the default connection, don't pass the
+ connection name argument when you call addDatabase().
+ Subsequently, when you call any static member function that takes
+ the connection name argument, if you don't pass the connection
+ name argument, the default connection is assumed. The following
+ snippet shows how to create and open a default connection to a
+ PostgreSQL database:
+
+ \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 0
+
+ Once the QSqlDatabase object has been created, set the connection
+ parameters with setDatabaseName(), setUserName(), setPassword(),
+ setHostName(), setPort(), and setConnectOptions(). Then call
+ open() to activate the physical connection to the database. The
+ connection is not usable until you open it.
+
+ The connection defined above will be the \e{default} connection,
+ because we didn't give a connection name to \l{QSqlDatabase::}
+ {addDatabase()}. Subsequently, you can get the default connection
+ by calling database() without the connection name argument:
+
+ \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 1
+
+ QSqlDatabase is a value class. Changes made to a database
+ connection via one instance of QSqlDatabase will affect other
+ instances of QSqlDatabase that represent the same connection. Use
+ cloneDatabase() to create an independent database connection based
+ on an existing one.
+
+ If you create multiple database connections, specify a unique
+ connection name for each one, when you call addDatabase(). Use
+ database() with a connection name to get that connection. Use
+ removeDatabase() with a connection name to remove a connection.
+ QSqlDatabase outputs a warning if you try to remove a connection
+ referenced by other QSqlDatabase objects. Use contains() to see if
+ a given connection name is in the list of connections.
+
+ Once a connection is established, you can call tables() to get the
+ list of tables in the database, call primaryIndex() to get a
+ table's primary index, and call record() to get meta-information
+ about a table's fields (e.g., field names).
+
+ \note QSqlDatabase::exec() is deprecated. Use QSqlQuery::exec()
+ instead.
+
+ If the driver supports transactions, use transaction() to start a
+ transaction, and commit() or rollback() to complete it. Use
+ \l{QSqlDriver::} {hasFeature()} to ask if the driver supports
+ transactions. \note When using transactions, you must start the
+ transaction before you create your query.
+
+ If an error occurrs, lastError() will return information about it.
+
+ Get the names of the available SQL drivers with drivers(). Check
+ for the presence of a particular driver with isDriverAvailable().
+ If you have created your own custom driver, you must register it
+ with registerSqlDriver().
+
+ \sa QSqlDriver, QSqlQuery, {QtSql Module}, {Threads and the SQL Module}
+*/
+
+/*! \fn QSqlDatabase QSqlDatabase::addDatabase(const QString &type, const QString &connectionName)
+ \threadsafe
+
+ Adds a database to the list of database connections using the
+ driver \a type and the connection name \a connectionName. If
+ there already exists a database connection called \a
+ connectionName, that connection is removed.
+
+ The database connection is referred to by \a connectionName. The
+ newly added database connection is returned.
+
+ If \a type is not available or could not be loaded, isValid() returns false.
+
+ If \a connectionName is not specified, the new connection becomes
+ the default connection for the application, and subsequent calls
+ to database() without the connection name argument will return the
+ default connection. If a \a connectionName is provided here, use
+ database(\a connectionName) to retrieve the connection.
+
+ \warning If you add a connection with the same name as an existing
+ connection, the new connection replaces the old one. If you call
+ this function more than once without specifying \a connectionName,
+ the default connection will be the one replaced.
+
+ Before using the connection, it must be initialized. e.g., call
+ some or all of setDatabaseName(), setUserName(), setPassword(),
+ setHostName(), setPort(), and setConnectOptions(), and, finally,
+ open().
+
+ \sa database() removeDatabase() {Threads and the SQL Module}
+*/
+QSqlDatabase QSqlDatabase::addDatabase(const QString &type, const QString &connectionName)
+{
+ QSqlDatabase db(type);
+ QSqlDatabasePrivate::addDatabase(db, connectionName);
+ return db;
+}
+
+/*!
+ \threadsafe
+
+ Returns the database connection called \a connectionName. The
+ database connection must have been previously added with
+ addDatabase(). If \a open is true (the default) and the database
+ connection is not already open it is opened now. If no \a
+ connectionName is specified the default connection is used. If \a
+ connectionName does not exist in the list of databases, an invalid
+ connection is returned.
+
+ \sa isOpen() {Threads and the SQL Module}
+*/
+
+QSqlDatabase QSqlDatabase::database(const QString& connectionName, bool open)
+{
+ return QSqlDatabasePrivate::database(connectionName, open);
+}
+
+/*!
+ \threadsafe
+
+ Removes the database connection \a connectionName from the list of
+ database connections.
+
+ \warning There should be no open queries on the database
+ connection when this function is called, otherwise a resource leak
+ will occur.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 0
+
+ The correct way to do it:
+
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 1
+
+ To remove the default connection, which may have been created with a
+ call to addDatabase() not specifying a connection name, you can
+ retrieve the default connection name by calling connectionName() on
+ the database returned by database(). Note that if a default database
+ hasn't been created an invalid database will be returned.
+
+ \sa database() connectionName() {Threads and the SQL Module}
+*/
+
+void QSqlDatabase::removeDatabase(const QString& connectionName)
+{
+ QSqlDatabasePrivate::removeDatabase(connectionName);
+}
+
+/*!
+ Returns a list of all the available database drivers.
+
+ \sa registerSqlDriver()
+*/
+
+QStringList QSqlDatabase::drivers()
+{
+ QStringList list;
+
+#ifdef QT_SQL_PSQL
+ list << QLatin1String("QPSQL7");
+ list << QLatin1String("QPSQL");
+#endif
+#ifdef QT_SQL_MYSQL
+ list << QLatin1String("QMYSQL3");
+ list << QLatin1String("QMYSQL");
+#endif
+#ifdef QT_SQL_ODBC
+ list << QLatin1String("QODBC3");
+ list << QLatin1String("QODBC");
+#endif
+#ifdef QT_SQL_OCI
+ list << QLatin1String("QOCI8");
+ list << QLatin1String("QOCI");
+#endif
+#ifdef QT_SQL_TDS
+ list << QLatin1String("QTDS7");
+ list << QLatin1String("QTDS");
+#endif
+#ifdef QT_SQL_DB2
+ list << QLatin1String("QDB2");
+#endif
+#ifdef QT_SQL_SQLITE
+ list << QLatin1String("QSQLITE");
+#endif
+#ifdef QT_SQL_SQLITE2
+ list << QLatin1String("QSQLITE2");
+#endif
+#ifdef QT_SQL_IBASE
+ list << QLatin1String("QIBASE");
+#endif
+
+#ifndef QT_NO_LIBRARY
+ if (QFactoryLoader *fl = loader()) {
+ QStringList keys = fl->keys();
+ for (QStringList::const_iterator i = keys.constBegin(); i != keys.constEnd(); ++i) {
+ if (!list.contains(*i))
+ list << *i;
+ }
+ }
+#endif
+
+ DriverDict dict = QSqlDatabasePrivate::driverDict();
+ for (DriverDict::const_iterator i = dict.constBegin(); i != dict.constEnd(); ++i) {
+ if (!list.contains(i.key()))
+ list << i.key();
+ }
+
+ return list;
+}
+
+/*!
+ This function registers a new SQL driver called \a name, within
+ the SQL framework. This is useful if you have a custom SQL driver
+ and don't want to compile it as a plugin.
+
+ Example:
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 2
+
+ QSqlDatabase takes ownership of the \a creator pointer, so you
+ mustn't delete it yourself.
+
+ \sa drivers()
+*/
+void QSqlDatabase::registerSqlDriver(const QString& name, QSqlDriverCreatorBase *creator)
+{
+ delete QSqlDatabasePrivate::driverDict().take(name);
+ if (creator)
+ QSqlDatabasePrivate::driverDict().insert(name, creator);
+}
+
+/*!
+ \threadsafe
+
+ Returns true if the list of database connections contains \a
+ connectionName; otherwise returns false.
+
+ \sa connectionNames(), database(), {Threads and the SQL Module}
+*/
+
+bool QSqlDatabase::contains(const QString& connectionName)
+{
+ return dbDict()->contains_ts(connectionName);
+}
+
+/*!
+ \threadsafe
+
+ Returns a list containing the names of all connections.
+
+ \sa contains(), database(), {Threads and the SQL Module}
+*/
+QStringList QSqlDatabase::connectionNames()
+{
+ return dbDict()->keys_ts();
+}
+
+/*!
+ \overload
+
+ Creates a QSqlDatabase connection that uses the driver referred
+ to by \a type. If the \a type is not recognized, the database
+ connection will have no functionality.
+
+ The currently available driver types are:
+
+ \table
+ \header \i Driver Type \i Description
+ \row \i QDB2 \i IBM DB2
+ \row \i QIBASE \i Borland InterBase Driver
+ \row \i QMYSQL \i MySQL Driver
+ \row \i QOCI \i Oracle Call Interface Driver
+ \row \i QODBC \i ODBC Driver (includes Microsoft SQL Server)
+ \row \i QPSQL \i PostgreSQL Driver
+ \row \i QSQLITE \i SQLite version 3 or above
+ \row \i QSQLITE2 \i SQLite version 2
+ \row \i QTDS \i Sybase Adaptive Server
+ \endtable
+
+ Additional third party drivers, including your own custom
+ drivers, can be loaded dynamically.
+
+ \sa {SQL Database Drivers}, registerSqlDriver(), drivers()
+*/
+
+QSqlDatabase::QSqlDatabase(const QString &type)
+{
+ d = new QSqlDatabasePrivate(this);
+ d->init(type);
+}
+
+/*!
+ \overload
+
+ Creates a database connection using the given \a driver.
+*/
+
+QSqlDatabase::QSqlDatabase(QSqlDriver *driver)
+{
+ d = new QSqlDatabasePrivate(this, driver);
+}
+
+/*!
+ Creates an empty, invalid QSqlDatabase object. Use addDatabase(),
+ removeDatabase(), and database() to get valid QSqlDatabase
+ objects.
+*/
+QSqlDatabase::QSqlDatabase()
+{
+ d = QSqlDatabasePrivate::shared_null();
+ d->ref.ref();
+}
+
+/*!
+ Creates a copy of \a other.
+*/
+QSqlDatabase::QSqlDatabase(const QSqlDatabase &other)
+{
+ d = other.d;
+ d->ref.ref();
+}
+
+/*!
+ Assigns \a other to this object.
+*/
+QSqlDatabase &QSqlDatabase::operator=(const QSqlDatabase &other)
+{
+ qAtomicAssign(d, other.d);
+ return *this;
+}
+
+/*!
+ \internal
+
+ Create the actual driver instance \a type.
+*/
+
+void QSqlDatabasePrivate::init(const QString &type)
+{
+ drvName = type;
+
+ if (!driver) {
+#ifdef QT_SQL_PSQL
+ if (type == QLatin1String("QPSQL") || type == QLatin1String("QPSQL7"))
+ driver = new QPSQLDriver();
+#endif
+#ifdef QT_SQL_MYSQL
+ if (type == QLatin1String("QMYSQL") || type == QLatin1String("QMYSQL3"))
+ driver = new QMYSQLDriver();
+#endif
+#ifdef QT_SQL_ODBC
+ if (type == QLatin1String("QODBC") || type == QLatin1String("QODBC3"))
+ driver = new QODBCDriver();
+#endif
+#ifdef QT_SQL_OCI
+ if (type == QLatin1String("QOCI") || type == QLatin1String("QOCI8"))
+ driver = new QOCIDriver();
+#endif
+#ifdef QT_SQL_TDS
+ if (type == QLatin1String("QTDS") || type == QLatin1String("QTDS7"))
+ driver = new QTDSDriver();
+#endif
+#ifdef QT_SQL_DB2
+ if (type == QLatin1String("QDB2"))
+ driver = new QDB2Driver();
+#endif
+#ifdef QT_SQL_SQLITE
+ if (type == QLatin1String("QSQLITE"))
+ driver = new QSQLiteDriver();
+#endif
+#ifdef QT_SQL_SQLITE2
+ if (type == QLatin1String("QSQLITE2"))
+ driver = new QSQLite2Driver();
+#endif
+#ifdef QT_SQL_IBASE
+ if (type == QLatin1String("QIBASE"))
+ driver = new QIBaseDriver();
+#endif
+ }
+
+ if (!driver) {
+ DriverDict dict = QSqlDatabasePrivate::driverDict();
+ for (DriverDict::const_iterator it = dict.constBegin();
+ it != dict.constEnd() && !driver; ++it) {
+ if (type == it.key()) {
+ driver = ((QSqlDriverCreatorBase*)(*it))->createObject();
+ }
+ }
+ }
+
+#ifndef QT_NO_LIBRARY
+ if (!driver && loader()) {
+ if (QSqlDriverFactoryInterface *factory = qobject_cast<QSqlDriverFactoryInterface*>(loader()->instance(type)))
+ driver = factory->create(type);
+ }
+#endif // QT_NO_LIBRARY
+
+ if (!driver) {
+ qWarning("QSqlDatabase: %s driver not loaded", type.toLatin1().data());
+ qWarning("QSqlDatabase: available drivers: %s",
+ QSqlDatabase::drivers().join(QLatin1String(" ")).toLatin1().data());
+ if (QCoreApplication::instance() == 0)
+ qWarning("QSqlDatabase: an instance of QCoreApplication is required for loading driver plugins");
+ driver = shared_null()->driver;
+ }
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+
+ If this is the last QSqlDatabase object that uses a certain
+ database connection, the database connection is automatically closed.
+
+ \sa close()
+*/
+
+QSqlDatabase::~QSqlDatabase()
+{
+ if (!d->ref.deref()) {
+ close();
+ delete d;
+ }
+}
+
+/*!
+ Executes a SQL statement on the database and returns a QSqlQuery
+ object. Use lastError() to retrieve error information. If \a
+ query is empty, an empty, invalid query is returned and
+ lastError() is not affected.
+
+ \sa QSqlQuery, lastError()
+*/
+
+QSqlQuery QSqlDatabase::exec(const QString & query) const
+{
+ QSqlQuery r(d->driver->createResult());
+ if (!query.isEmpty()) {
+ r.exec(query);
+ d->driver->setLastError(r.lastError());
+ }
+ return r;
+}
+
+/*!
+ Opens the database connection using the current connection
+ values. Returns true on success; otherwise returns false. Error
+ information can be retrieved using lastError().
+
+ \sa lastError() setDatabaseName() setUserName() setPassword()
+ \sa setHostName() setPort() setConnectOptions()
+*/
+
+bool QSqlDatabase::open()
+{
+ return d->driver->open(d->dbname, d->uname, d->pword, d->hname,
+ d->port, d->connOptions);
+}
+
+/*!
+ \overload
+
+ Opens the database connection using the given \a user name and \a
+ password. Returns true on success; otherwise returns false. Error
+ information can be retrieved using the lastError() function.
+
+ This function does not store the password it is given. Instead,
+ the password is passed directly to the driver for opening the
+ connection and it is then discarded.
+
+ \sa lastError()
+*/
+
+bool QSqlDatabase::open(const QString& user, const QString& password)
+{
+ setUserName(user);
+ return d->driver->open(d->dbname, user, password, d->hname,
+ d->port, d->connOptions);
+}
+
+/*!
+ Closes the database connection, freeing any resources acquired, and
+ invalidating any existing QSqlQuery objects that are used with the
+ database.
+
+ This will also affect copies of this QSqlDatabase object.
+
+ \sa removeDatabase()
+*/
+
+void QSqlDatabase::close()
+{
+ d->driver->close();
+}
+
+/*!
+ Returns true if the database connection is currently open;
+ otherwise returns false.
+*/
+
+bool QSqlDatabase::isOpen() const
+{
+ return d->driver->isOpen();
+}
+
+/*!
+ Returns true if there was an error opening the database
+ connection; otherwise returns false. Error information can be
+ retrieved using the lastError() function.
+*/
+
+bool QSqlDatabase::isOpenError() const
+{
+ return d->driver->isOpenError();
+}
+
+/*!
+ Begins a transaction on the database if the driver supports
+ transactions. Returns \c{true} if the operation succeeded.
+ Otherwise it returns \c{false}.
+
+ \sa QSqlDriver::hasFeature(), commit(), rollback()
+*/
+bool QSqlDatabase::transaction()
+{
+ if (!d->driver->hasFeature(QSqlDriver::Transactions))
+ return false;
+ return d->driver->beginTransaction();
+}
+
+/*!
+ Commits a transaction to the database if the driver supports
+ transactions and a transaction() has been started. Returns \c{true}
+ if the operation succeeded. Otherwise it returns \c{false}.
+
+ \note For some databases, the commit will fail and return \c{false}
+ if there is an \l{QSqlQuery::isActive()} {active query} using the
+ database for a \c{SELECT}. Make the query \l{QSqlQuery::isActive()}
+ {inactive} before doing the commit.
+
+ Call lastError() to get information about errors.
+
+ \sa QSqlQuery::isActive() QSqlDriver::hasFeature() rollback()
+*/
+bool QSqlDatabase::commit()
+{
+ if (!d->driver->hasFeature(QSqlDriver::Transactions))
+ return false;
+ return d->driver->commitTransaction();
+}
+
+/*!
+ Rolls back a transaction on the database, if the driver supports
+ transactions and a transaction() has been started. Returns \c{true}
+ if the operation succeeded. Otherwise it returns \c{false}.
+
+ \note For some databases, the rollback will fail and return
+ \c{false} if there is an \l{QSqlQuery::isActive()} {active query}
+ using the database for a \c{SELECT}. Make the query
+ \l{QSqlQuery::isActive()} {inactive} before doing the rollback.
+
+ Call lastError() to get information about errors.
+
+ \sa QSqlQuery::isActive() QSqlDriver::hasFeature() commit()
+*/
+bool QSqlDatabase::rollback()
+{
+ if (!d->driver->hasFeature(QSqlDriver::Transactions))
+ return false;
+ return d->driver->rollbackTransaction();
+}
+
+/*!
+ Sets the connection's database name to \a name. To have effect,
+ the database name must be set \e{before} the connection is
+ \l{open()} {opened}. Alternatively, you can close() the
+ connection, set the database name, and call open() again. \note
+ The \e{database name} is not the \e{connection name}. The
+ connection name must be passed to addDatabase() at connection
+ object create time.
+
+ For the QOCI (Oracle) driver, the database name is the TNS
+ Service Name.
+
+ For the QODBC driver, the \a name can either be a DSN, a DSN
+ filename (in which case the file must have a \c .dsn extension),
+ or a connection string.
+
+ For example, Microsoft Access users can use the following
+ connection string to open an \c .mdb file directly, instead of
+ having to create a DSN entry in the ODBC manager:
+
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 3
+
+ There is no default value.
+
+ \sa databaseName() setUserName() setPassword() setHostName()
+ \sa setPort() setConnectOptions() open()
+*/
+
+void QSqlDatabase::setDatabaseName(const QString& name)
+{
+ if (isValid())
+ d->dbname = name;
+}
+
+/*!
+ Sets the connection's user name to \a name. To have effect, the
+ user name must be set \e{before} the connection is \l{open()}
+ {opened}. Alternatively, you can close() the connection, set the
+ user name, and call open() again.
+
+ There is no default value.
+
+ \sa userName() setDatabaseName() setPassword() setHostName()
+ \sa setPort() setConnectOptions() open()
+*/
+
+void QSqlDatabase::setUserName(const QString& name)
+{
+ if (isValid())
+ d->uname = name;
+}
+
+/*!
+ Sets the connection's password to \a password. To have effect, the
+ password must be set \e{before} the connection is \l{open()}
+ {opened}. Alternatively, you can close() the connection, set the
+ password, and call open() again.
+
+ There is no default value.
+
+ \warning This function stores the password in plain text within
+ Qt. Use the open() call that takes a password as parameter to
+ avoid this behavior.
+
+ \sa password() setUserName() setDatabaseName() setHostName()
+ \sa setPort() setConnectOptions() open()
+*/
+
+void QSqlDatabase::setPassword(const QString& password)
+{
+ if (isValid())
+ d->pword = password;
+}
+
+/*!
+ Sets the connection's host name to \a host. To have effect, the
+ host name must be set \e{before} the connection is \l{open()}
+ {opened}. Alternatively, you can close() the connection, set the
+ host name, and call open() again.
+
+ There is no default value.
+
+ \sa hostName() setUserName() setPassword() setDatabaseName()
+ \sa setPort() setConnectOptions() open()
+*/
+
+void QSqlDatabase::setHostName(const QString& host)
+{
+ if (isValid())
+ d->hname = host;
+}
+
+/*!
+ Sets the connection's port number to \a port. To have effect, the
+ port number must be set \e{before} the connection is \l{open()}
+ {opened}. Alternatively, you can close() the connection, set the
+ port number, and call open() again..
+
+ There is no default value.
+
+ \sa port() setUserName() setPassword() setHostName()
+ \sa setDatabaseName() setConnectOptions() open()
+*/
+
+void QSqlDatabase::setPort(int port)
+{
+ if (isValid())
+ d->port = port;
+}
+
+/*!
+ Returns the connection's database name, which may be empty.
+ \note The database name is not the connection name.
+
+ \sa setDatabaseName()
+*/
+QString QSqlDatabase::databaseName() const
+{
+ return d->dbname;
+}
+
+/*!
+ Returns the connection's user name; it may be empty.
+
+ \sa setUserName()
+*/
+QString QSqlDatabase::userName() const
+{
+ return d->uname;
+}
+
+/*!
+ Returns the connection's password. If the password was not set
+ with setPassword(), and if the password was given in the open()
+ call, or if no password was used, an empty string is returned.
+*/
+QString QSqlDatabase::password() const
+{
+ return d->pword;
+}
+
+/*!
+ Returns the connection's host name; it may be empty.
+
+ \sa setHostName()
+*/
+QString QSqlDatabase::hostName() const
+{
+ return d->hname;
+}
+
+/*!
+ Returns the connection's driver name.
+
+ \sa addDatabase(), driver()
+*/
+QString QSqlDatabase::driverName() const
+{
+ return d->drvName;
+}
+
+/*!
+ Returns the connection's port number. The value is undefined if
+ the port number has not been set.
+
+ \sa setPort()
+*/
+int QSqlDatabase::port() const
+{
+ return d->port;
+}
+
+/*!
+ Returns the database driver used to access the database
+ connection.
+
+ \sa addDatabase() drivers()
+*/
+
+QSqlDriver* QSqlDatabase::driver() const
+{
+ return d->driver;
+}
+
+/*!
+ Returns information about the last error that occurred on the
+ database.
+
+ Failures that occur in conjunction with an individual query are
+ reported by QSqlQuery::lastError().
+
+ \sa QSqlError, QSqlQuery::lastError()
+*/
+
+QSqlError QSqlDatabase::lastError() const
+{
+ return d->driver->lastError();
+}
+
+
+/*!
+ Returns a list of the database's tables, system tables and views,
+ as specified by the parameter \a type.
+
+ \sa primaryIndex(), record()
+*/
+
+QStringList QSqlDatabase::tables(QSql::TableType type) const
+{
+ return d->driver->tables(type);
+}
+
+/*!
+ Returns the primary index for table \a tablename. If no primary
+ index exists an empty QSqlIndex is returned.
+
+ \sa tables(), record()
+*/
+
+QSqlIndex QSqlDatabase::primaryIndex(const QString& tablename) const
+{
+ return d->driver->primaryIndex(tablename);
+}
+
+
+/*!
+ Returns a QSqlRecord populated with the names of all the fields in
+ the table (or view) called \a tablename. The order in which the
+ fields appear in the record is undefined. If no such table (or
+ view) exists, an empty record is returned.
+*/
+
+QSqlRecord QSqlDatabase::record(const QString& tablename) const
+{
+ return d->driver->record(tablename);
+}
+
+
+/*!
+ Sets database-specific \a options. This must be done before the
+ connection is opened or it has no effect (or you can close() the
+ connection, call this function and open() the connection again).
+
+ The format of the \a options string is a semicolon separated list
+ of option names or option=value pairs. The options depend on the
+ database client used:
+
+ \table
+ \header \i ODBC \i MySQL \i PostgreSQL
+ \row
+
+ \i
+ \list
+ \i SQL_ATTR_ACCESS_MODE
+ \i SQL_ATTR_LOGIN_TIMEOUT
+ \i SQL_ATTR_CONNECTION_TIMEOUT
+ \i SQL_ATTR_CURRENT_CATALOG
+ \i SQL_ATTR_METADATA_ID
+ \i SQL_ATTR_PACKET_SIZE
+ \i SQL_ATTR_TRACEFILE
+ \i SQL_ATTR_TRACE
+ \i SQL_ATTR_CONNECTION_POOLING
+ \i SQL_ATTR_ODBC_VERSION
+ \endlist
+
+ \i
+ \list
+ \i CLIENT_COMPRESS
+ \i CLIENT_FOUND_ROWS
+ \i CLIENT_IGNORE_SPACE
+ \i CLIENT_SSL
+ \i CLIENT_ODBC
+ \i CLIENT_NO_SCHEMA
+ \i CLIENT_INTERACTIVE
+ \i UNIX_SOCKET
+ \i MYSQL_OPT_RECONNECT
+ \endlist
+
+ \i
+ \list
+ \i connect_timeout
+ \i options
+ \i tty
+ \i requiressl
+ \i service
+ \endlist
+
+ \header \i DB2 \i OCI \i TDS
+ \row
+
+ \i
+ \list
+ \i SQL_ATTR_ACCESS_MODE
+ \i SQL_ATTR_LOGIN_TIMEOUT
+ \endlist
+
+ \i
+ \list
+ \i OCI_ATTR_PREFETCH_ROWS
+ \i OCI_ATTR_PREFETCH_MEMORY
+ \endlist
+
+ \i
+ \e none
+
+ \header \i SQLite \i Interbase
+ \row
+
+ \i
+ \list
+ \i QSQLITE_BUSY_TIMEOUT
+ \i QSQLITE_OPEN_READONLY
+ \i QSQLITE_ENABLE_SHARED_CACHE
+ \endlist
+
+ \i
+ \list
+ \i ISC_DPB_LC_CTYPE
+ \i ISC_DPB_SQL_ROLE_NAME
+ \endlist
+
+ \endtable
+
+ Examples:
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 4
+
+ Refer to the client library documentation for more information
+ about the different options.
+
+ \sa connectOptions()
+*/
+
+void QSqlDatabase::setConnectOptions(const QString &options)
+{
+ if (isValid())
+ d->connOptions = options;
+}
+
+/*!
+ Returns the connection options string used for this connection.
+ The string may be empty.
+
+ \sa setConnectOptions()
+ */
+QString QSqlDatabase::connectOptions() const
+{
+ return d->connOptions;
+}
+
+/*!
+ Returns true if a driver called \a name is available; otherwise
+ returns false.
+
+ \sa drivers()
+*/
+
+bool QSqlDatabase::isDriverAvailable(const QString& name)
+{
+ return drivers().contains(name);
+}
+
+/*! \fn QSqlDatabase QSqlDatabase::addDatabase(QSqlDriver* driver, const QString& connectionName)
+
+ This overload is useful when you want to create a database
+ connection with a \l{QSqlDriver} {driver} you instantiated
+ yourself. It might be your own database driver, or you might just
+ need to instantiate one of the Qt drivers yourself. If you do
+ this, it is recommended that you include the driver code in your
+ application. For example, you can create a PostgreSQL connection
+ with your own QPSQL driver like this:
+
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 5
+ \codeline
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 6
+
+ The above code sets up a PostgreSQL connection and instantiates a
+ QPSQLDriver object. Next, addDatabase() is called to add the
+ connection to the known connections so that it can be used by the
+ Qt SQL classes. When a driver is instantiated with a connection
+ handle (or set of handles), Qt assumes that you have already
+ opened the database connection.
+
+ \note We assume that \c qtdir is the directory where Qt is
+ installed. This will pull in the code that is needed to use the
+ PostgreSQL client library and to instantiate a QPSQLDriver object,
+ assuming that you have the PostgreSQL headers somewhere in your
+ include search path.
+
+ Remember that you must link your application against the database
+ client library. Make sure the client library is in your linker's
+ search path, and add lines like these to your \c{.pro} file:
+
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 7
+
+ The method described works for all the supplied drivers. The only
+ difference will be in the driver constructor arguments. Here is a
+ table of the drivers included with Qt, their source code files,
+ and their constructor arguments:
+
+ \table
+ \header \i Driver \i Class name \i Constructor arguments \i File to include
+ \row
+ \i QPSQL
+ \i QPSQLDriver
+ \i PGconn *connection
+ \i \c qsql_psql.cpp
+ \row
+ \i QMYSQL
+ \i QMYSQLDriver
+ \i MYSQL *connection
+ \i \c qsql_mysql.cpp
+ \row
+ \i QOCI
+ \i QOCIDriver
+ \i OCIEnv *environment, OCISvcCtx *serviceContext
+ \i \c qsql_oci.cpp
+ \row
+ \i QODBC
+ \i QODBCDriver
+ \i SQLHANDLE environment, SQLHANDLE connection
+ \i \c qsql_odbc.cpp
+ \row
+ \i QDB2
+ \i QDB2
+ \i SQLHANDLE environment, SQLHANDLE connection
+ \i \c qsql_db2.cpp
+ \row
+ \i QTDS
+ \i QTDSDriver
+ \i LOGINREC *loginRecord, DBPROCESS *dbProcess, const QString &hostName
+ \i \c qsql_tds.cpp
+ \row
+ \i QSQLITE
+ \i QSQLiteDriver
+ \i sqlite *connection
+ \i \c qsql_sqlite.cpp
+ \row
+ \i QIBASE
+ \i QIBaseDriver
+ \i isc_db_handle connection
+ \i \c qsql_ibase.cpp
+ \endtable
+
+ The host name (or service name) is needed when constructing the
+ QTDSDriver for creating new connections for internal queries. This
+ is to prevent blocking when several QSqlQuery objects are used
+ simultaneously.
+
+ \warning Adding a database connection with the same connection
+ name as an existing connection, causes the existing connection to
+ be replaced by the new one.
+
+ \warning The SQL framework takes ownership of the \a driver. It
+ must not be deleted. To remove the connection, use
+ removeDatabase().
+
+ \sa drivers()
+*/
+QSqlDatabase QSqlDatabase::addDatabase(QSqlDriver* driver, const QString& connectionName)
+{
+ QSqlDatabase db(driver);
+ QSqlDatabasePrivate::addDatabase(db, connectionName);
+ return db;
+}
+
+/*!
+ Returns true if the QSqlDatabase has a valid driver.
+
+ Example:
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqldatabase.cpp 8
+*/
+bool QSqlDatabase::isValid() const
+{
+ return d->driver && d->driver != d->shared_null()->driver;
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Use query.record() instead.
+*/
+QSqlRecord QSqlDatabase::record(const QSqlQuery& query) const
+{ return query.record(); }
+
+/*!
+ Use query.record() instead.
+*/
+QSqlRecord QSqlDatabase::recordInfo(const QSqlQuery& query) const
+{ return query.record(); }
+
+/*!
+ \fn QSqlRecord QSqlDatabase::recordInfo(const QString& tablename) const
+
+ Use record() instead.
+*/
+#endif
+
+/*!
+ Clones the database connection \a other and and stores it as \a
+ connectionName. All the settings from the original database, e.g.
+ databaseName(), hostName(), etc., are copied across. Does nothing
+ if \a other is an invalid database. Returns the newly created
+ database connection.
+
+ \note The new connection has not been opened. Before using the new
+ connection, you must call open().
+*/
+QSqlDatabase QSqlDatabase::cloneDatabase(const QSqlDatabase &other, const QString &connectionName)
+{
+ if (!other.isValid())
+ return QSqlDatabase();
+
+ QSqlDatabase db(other.driverName());
+ db.d->copy(other.d);
+ QSqlDatabasePrivate::addDatabase(db, connectionName);
+ return db;
+}
+
+/*!
+ \since 4.4
+
+ Returns the connection name, which may be empty. \note The
+ connection name is not the \l{databaseName()} {database name}.
+
+ \sa addDatabase()
+*/
+QString QSqlDatabase::connectionName() const
+{
+ return d->connName;
+}
+
+/*!
+ \since 4.6
+
+ Sets the default numerical precision policy used by queries created
+ on this database connection to \a precisionPolicy.
+
+ 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 default precision policy to \a precisionPolicy
+ doesn't affect any currently active queries.
+
+ \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy(),
+ QSqlQuery::setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy()
+*/
+void QSqlDatabase::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy)
+{
+ if(driver())
+ driver()->setNumericalPrecisionPolicy(precisionPolicy);
+ d->precisionPolicy = precisionPolicy;
+}
+
+/*!
+ \since 4.6
+
+ Returns the current default precision policy for the database connection.
+
+ \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy(),
+ QSqlQuery::numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy()
+*/
+QSql::NumericalPrecisionPolicy QSqlDatabase::numericalPrecisionPolicy() const
+{
+ if(driver())
+ return driver()->numericalPrecisionPolicy();
+ else
+ return d->precisionPolicy;
+}
+
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QSqlDatabase &d)
+{
+ if (!d.isValid()) {
+ dbg.nospace() << "QSqlDatabase(invalid)";
+ return dbg.space();
+ }
+
+ dbg.nospace() << "QSqlDatabase(driver=\"" << d.driverName() << "\", database=\""
+ << d.databaseName() << "\", host=\"" << d.hostName() << "\", port=" << d.port()
+ << ", user=\"" << d.userName() << "\", open=" << d.isOpen() << ")";
+ return dbg.space();
+}
+#endif
+
+QT_END_NAMESPACE
diff --git a/src/sql/kernel/qsqldatabase.h b/src/sql/kernel/qsqldatabase.h
new file mode 100644
index 0000000000..00fccd6161
--- /dev/null
+++ b/src/sql/kernel/qsqldatabase.h
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQLDATABASE_H
+#define QSQLDATABASE_H
+
+#include <QtCore/qstring.h>
+#include <QtSql/qsql.h>
+#ifdef QT3_SUPPORT
+#include <QtSql/qsqlrecord.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sql)
+
+class QSqlError;
+class QSqlDriver;
+class QSqlIndex;
+class QSqlRecord;
+class QSqlQuery;
+class QSqlDatabasePrivate;
+
+class Q_SQL_EXPORT QSqlDriverCreatorBase
+{
+public:
+ virtual ~QSqlDriverCreatorBase() {}
+ virtual QSqlDriver *createObject() const = 0;
+};
+
+template <class T>
+class QSqlDriverCreator : public QSqlDriverCreatorBase
+{
+public:
+ QSqlDriver *createObject() const { return new T; }
+};
+
+class Q_SQL_EXPORT QSqlDatabase
+{
+public:
+ QSqlDatabase();
+ QSqlDatabase(const QSqlDatabase &other);
+ ~QSqlDatabase();
+
+ QSqlDatabase &operator=(const QSqlDatabase &other);
+
+ bool open();
+ bool open(const QString& user, const QString& password);
+ void close();
+ bool isOpen() const;
+ bool isOpenError() const;
+ QStringList tables(QSql::TableType type = QSql::Tables) const;
+ QSqlIndex primaryIndex(const QString& tablename) const;
+ QSqlRecord record(const QString& tablename) const;
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT QSqlRecord record(const QSqlQuery& query) const;
+ inline QT3_SUPPORT QSqlRecord recordInfo(const QString& tablename) const
+ { return record(tablename); }
+ QT3_SUPPORT QSqlRecord recordInfo(const QSqlQuery& query) const;
+#endif
+ QSqlQuery exec(const QString& query = QString()) const;
+ QSqlError lastError() const;
+ bool isValid() const;
+
+ bool transaction();
+ bool commit();
+ bool rollback();
+
+ void setDatabaseName(const QString& name);
+ void setUserName(const QString& name);
+ void setPassword(const QString& password);
+ void setHostName(const QString& host);
+ void setPort(int p);
+ void setConnectOptions(const QString& options = QString());
+ QString databaseName() const;
+ QString userName() const;
+ QString password() const;
+ QString hostName() const;
+ QString driverName() const;
+ int port() const;
+ QString connectOptions() const;
+ QString connectionName() const;
+ void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy);
+ QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
+
+ QSqlDriver* driver() const;
+
+ QT_STATIC_CONST char *defaultConnection;
+
+ static QSqlDatabase addDatabase(const QString& type,
+ const QString& connectionName = QLatin1String(defaultConnection));
+ static QSqlDatabase addDatabase(QSqlDriver* driver,
+ const QString& connectionName = QLatin1String(defaultConnection));
+ static QSqlDatabase cloneDatabase(const QSqlDatabase &other, const QString& connectionName);
+ static QSqlDatabase database(const QString& connectionName = QLatin1String(defaultConnection),
+ bool open = true);
+ static void removeDatabase(const QString& connectionName);
+ static bool contains(const QString& connectionName = QLatin1String(defaultConnection));
+ static QStringList drivers();
+ static QStringList connectionNames();
+ static void registerSqlDriver(const QString &name, QSqlDriverCreatorBase *creator);
+ static bool isDriverAvailable(const QString &name);
+
+protected:
+ explicit QSqlDatabase(const QString& type);
+ explicit QSqlDatabase(QSqlDriver* driver);
+
+private:
+ friend class QSqlDatabasePrivate;
+ QSqlDatabasePrivate *d;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_SQL_EXPORT QDebug operator<<(QDebug, const QSqlDatabase &);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSQLDATABASE_H
diff --git a/src/sql/kernel/qsqldriver.cpp b/src/sql/kernel/qsqldriver.cpp
new file mode 100644
index 0000000000..bbec21dc0a
--- /dev/null
+++ b/src/sql/kernel/qsqldriver.cpp
@@ -0,0 +1,948 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qsqldriver.h"
+
+#include "qdatetime.h"
+#include "qsqlerror.h"
+#include "qsqlfield.h"
+#include "qsqlindex.h"
+#include "private/qobject_p.h"
+
+QT_BEGIN_NAMESPACE
+
+static QString prepareIdentifier(const QString &identifier,
+ QSqlDriver::IdentifierType type, const QSqlDriver *driver)
+{
+ Q_ASSERT( driver != NULL );
+ QString ret = identifier;
+ if (!driver->isIdentifierEscaped(identifier, type)) {
+ ret = driver->escapeIdentifier(identifier, type);
+ }
+ return ret;
+}
+
+class QSqlDriverPrivate : public QObjectPrivate
+{
+public:
+ QSqlDriverPrivate();
+ virtual ~QSqlDriverPrivate();
+
+public:
+ // @CHECK: this member is never used. It was named q, which expanded to q_func().
+ QSqlDriver *q_func();
+ uint isOpen : 1;
+ uint isOpenError : 1;
+ QSqlError error;
+ QSql::NumericalPrecisionPolicy precisionPolicy;
+};
+
+inline QSqlDriverPrivate::QSqlDriverPrivate()
+ : QObjectPrivate(), isOpen(false), isOpenError(false), precisionPolicy(QSql::LowPrecisionDouble)
+{
+}
+
+QSqlDriverPrivate::~QSqlDriverPrivate()
+{
+}
+
+/*!
+ \class QSqlDriver
+ \brief The QSqlDriver class is an abstract base class for accessing
+ specific SQL databases.
+
+ \ingroup database
+ \inmodule QtSql
+
+ This class should not be used directly. Use QSqlDatabase instead.
+
+ If you want to create your own SQL drivers, you can subclass this
+ class and reimplement its pure virtual functions and those
+ virtual functions that you need. See \l{How to Write Your Own
+ Database Driver} for more information.
+
+ \sa QSqlDatabase, QSqlResult
+*/
+
+/*!
+ Constructs a new driver with the given \a parent.
+*/
+
+QSqlDriver::QSqlDriver(QObject *parent)
+ : QObject(*new QSqlDriverPrivate, parent)
+{
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QSqlDriver::~QSqlDriver()
+{
+}
+
+/*!
+ \since 4.4
+
+ \fn QSqlDriver::notification(const QString &name)
+
+ This signal is emitted when the database posts an event notification
+ that the driver subscribes to. \a name identifies the event notification.
+
+ \sa subscribeToNotification()
+*/
+
+/*!
+ \fn bool QSqlDriver::open(const QString &db, const QString &user, const QString& password,
+ const QString &host, int port, const QString &options)
+
+ Derived classes must reimplement this pure virtual function to
+ open a database connection on database \a db, using user name \a
+ user, password \a password, host \a host, port \a port and
+ connection options \a options.
+
+ The function must return true on success and false on failure.
+
+ \sa setOpen()
+*/
+
+/*!
+ \fn bool QSqlDriver::close()
+
+ Derived classes must reimplement this pure virtual function in
+ order to close the database connection. Return true on success,
+ false on failure.
+
+ \sa open(), setOpen()
+*/
+
+/*!
+ \fn QSqlResult *QSqlDriver::createResult() const
+
+ Creates an empty SQL result on the database. Derived classes must
+ reimplement this function and return a QSqlResult object
+ appropriate for their database to the caller.
+*/
+
+/*!
+ Returns true if the database connection is open; otherwise returns
+ false.
+*/
+
+bool QSqlDriver::isOpen() const
+{
+ return d_func()->isOpen;
+}
+
+/*!
+ Returns true if the there was an error opening the database
+ connection; otherwise returns false.
+*/
+
+bool QSqlDriver::isOpenError() const
+{
+ return d_func()->isOpenError;
+}
+
+/*!
+ \enum QSqlDriver::DriverFeature
+
+ This enum contains a list of features a driver might support. Use
+ hasFeature() to query whether a feature is supported or not.
+
+ \value Transactions Whether the driver supports SQL transactions.
+ \value QuerySize Whether the database is capable of reporting the size
+ of a query. Note that some databases do not support returning the size
+ (i.e. number of rows returned) of a query, in which case
+ QSqlQuery::size() will return -1.
+ \value BLOB Whether the driver supports Binary Large Object fields.
+ \value Unicode Whether the driver supports Unicode strings if the
+ database server does.
+ \value PreparedQueries Whether the driver supports prepared query execution.
+ \value NamedPlaceholders Whether the driver supports the use of named placeholders.
+ \value PositionalPlaceholders Whether the driver supports the use of positional placeholders.
+ \value LastInsertId Whether the driver supports returning the Id of the last touched row.
+ \value BatchOperations Whether the driver supports batched operations, see QSqlQuery::execBatch()
+ \value SimpleLocking Whether the driver disallows a write lock on a table while other queries have a read lock on it.
+ \value LowPrecisionNumbers Whether the driver allows fetching numerical values with low precision.
+ \value EventNotifications Whether the driver supports database event notifications.
+ \value FinishQuery Whether the driver can do any low-level resource cleanup when QSqlQuery::finish() is called.
+ \value MultipleResultSets Whether the driver can access multiple result sets returned from batched statements or stored procedures.
+
+ More information about supported features can be found in the
+ \l{sql-driver.html}{Qt SQL driver} documentation.
+
+ \sa hasFeature()
+*/
+
+/*!
+ \enum QSqlDriver::StatementType
+
+ This enum contains a list of SQL statement (or clause) types the
+ driver can create.
+
+ \value WhereStatement An SQL \c WHERE statement (e.g., \c{WHERE f = 5}).
+ \value SelectStatement An SQL \c SELECT statement (e.g., \c{SELECT f FROM t}).
+ \value UpdateStatement An SQL \c UPDATE statement (e.g., \c{UPDATE TABLE t set f = 1}).
+ \value InsertStatement An SQL \c INSERT statement (e.g., \c{INSERT INTO t (f) values (1)}).
+ \value DeleteStatement An SQL \c DELETE statement (e.g., \c{DELETE FROM t}).
+
+ \sa sqlStatement()
+*/
+
+/*!
+ \enum QSqlDriver::IdentifierType
+
+ This enum contains a list of SQL identifier types.
+
+ \value FieldName A SQL field name
+ \value TableName A SQL table name
+*/
+
+/*!
+ \fn bool QSqlDriver::hasFeature(DriverFeature feature) const
+
+ Returns true if the driver supports feature \a feature; otherwise
+ returns false.
+
+ Note that some databases need to be open() before this can be
+ determined.
+
+ \sa DriverFeature
+*/
+
+/*!
+ This function sets the open state of the database to \a open.
+ Derived classes can use this function to report the status of
+ open().
+
+ \sa open(), setOpenError()
+*/
+
+void QSqlDriver::setOpen(bool open)
+{
+ d_func()->isOpen = open;
+}
+
+/*!
+ This function sets the open error state of the database to \a
+ error. Derived classes can use this function to report the status
+ of open(). Note that if \a error is true the open state of the
+ database is set to closed (i.e., isOpen() returns false).
+
+ \sa open(), setOpen()
+*/
+
+void QSqlDriver::setOpenError(bool error)
+{
+ d_func()->isOpenError = error;
+ if (error)
+ d_func()->isOpen = false;
+}
+
+/*!
+ This function is called to begin a transaction. If successful,
+ return true, otherwise return false. The default implementation
+ does nothing and returns false.
+
+ \sa commitTransaction(), rollbackTransaction()
+*/
+
+bool QSqlDriver::beginTransaction()
+{
+ return false;
+}
+
+/*!
+ This function is called to commit a transaction. If successful,
+ return true, otherwise return false. The default implementation
+ does nothing and returns false.
+
+ \sa beginTransaction(), rollbackTransaction()
+*/
+
+bool QSqlDriver::commitTransaction()
+{
+ return false;
+}
+
+/*!
+ This function is called to rollback a transaction. If successful,
+ return true, otherwise return false. The default implementation
+ does nothing and returns false.
+
+ \sa beginTransaction(), commitTransaction()
+*/
+
+bool QSqlDriver::rollbackTransaction()
+{
+ return false;
+}
+
+/*!
+ This function is used to set the value of the last error, \a error,
+ that occurred on the database.
+
+ \sa lastError()
+*/
+
+void QSqlDriver::setLastError(const QSqlError &error)
+{
+ d_func()->error = error;
+}
+
+/*!
+ Returns a QSqlError object which contains information about the
+ last error that occurred on the database.
+*/
+
+QSqlError QSqlDriver::lastError() const
+{
+ return d_func()->error;
+}
+
+/*!
+ Returns a list of the names of the tables in the database. The
+ default implementation returns an empty list.
+
+ The \a tableType argument describes what types of tables
+ should be returned. Due to binary compatibility, the string
+ contains the value of the enum QSql::TableTypes as text.
+ An empty string should be treated as QSql::Tables for
+ backward compatibility.
+*/
+
+QStringList QSqlDriver::tables(QSql::TableType) const
+{
+ return QStringList();
+}
+
+/*!
+ Returns the primary index for table \a tableName. Returns an empty
+ QSqlIndex if the table doesn't have a primary index. The default
+ implementation returns an empty index.
+*/
+
+QSqlIndex QSqlDriver::primaryIndex(const QString&) const
+{
+ return QSqlIndex();
+}
+
+
+/*!
+ Returns a QSqlRecord populated with the names of the fields in
+ table \a tableName. If no such table exists, an empty record is
+ returned. The default implementation returns an empty record.
+*/
+
+QSqlRecord QSqlDriver::record(const QString & /* tableName */) const
+{
+ return QSqlRecord();
+}
+
+/*!
+ Returns the \a identifier escaped according to the database rules.
+ \a identifier can either be a table name or field name, dependent
+ on \a type.
+
+ The default implementation does nothing.
+ \sa isIdentifierEscaped()
+ */
+QString QSqlDriver::escapeIdentifier(const QString &identifier, IdentifierType) const
+{
+ return identifier;
+}
+
+/*!
+ Returns whether \a identifier is escaped according to the database rules.
+ \a identifier can either be a table name or field name, dependent
+ on \a type.
+
+ \warning Because of binary compatibility constraints, this function is not virtual.
+ If you want to provide your own implementation in your QSqlDriver subclass,
+ reimplement the isIdentifierEscapedImplementation() slot in your subclass instead.
+ The isIdentifierEscapedFunction() will dynamically detect the slot and call it.
+
+ \sa stripDelimiters(), escapeIdentifier()
+ */
+bool QSqlDriver::isIdentifierEscaped(const QString &identifier, IdentifierType type) const
+{
+ bool result;
+ QMetaObject::invokeMethod(const_cast<QSqlDriver*>(this),
+ "isIdentifierEscapedImplementation", Qt::DirectConnection,
+ Q_RETURN_ARG(bool, result),
+ Q_ARG(QString, identifier),
+ Q_ARG(IdentifierType, type));
+ return result;
+}
+
+/*!
+ Returns the \a identifier with the leading and trailing delimiters removed,
+ \a identifier can either be a table name or field name,
+ dependent on \a type. If \a identifier does not have leading
+ and trailing delimiter characters, \a identifier is returned without
+ modification.
+
+ \warning Because of binary compatibility constraints, this function is not virtual,
+ If you want to provide your own implementation in your QSqlDriver subclass,
+ reimplement the stripDelimitersImplementation() slot in your subclass instead.
+ The stripDelimiters() function will dynamically detect the slot and call it.
+
+ \since 4.5
+ \sa isIdentifierEscaped()
+ */
+QString QSqlDriver::stripDelimiters(const QString &identifier, IdentifierType type) const
+{
+ QString result;
+ QMetaObject::invokeMethod(const_cast<QSqlDriver*>(this),
+ "stripDelimitersImplementation", Qt::DirectConnection,
+ Q_RETURN_ARG(QString, result),
+ Q_ARG(QString, identifier),
+ Q_ARG(IdentifierType, type));
+ return result;
+}
+
+/*!
+ Returns a SQL statement of type \a type for the table \a tableName
+ with the values from \a rec. If \a preparedStatement is true, the
+ string will contain placeholders instead of values.
+
+ This method can be used to manipulate tables without having to worry
+ about database-dependent SQL dialects. For non-prepared statements,
+ the values will be properly escaped.
+*/
+QString QSqlDriver::sqlStatement(StatementType type, const QString &tableName,
+ const QSqlRecord &rec, bool preparedStatement) const
+{
+ int i;
+ QString s;
+ s.reserve(128);
+ switch (type) {
+ case SelectStatement:
+ for (i = 0; i < rec.count(); ++i) {
+ if (rec.isGenerated(i))
+ s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this)).append(QLatin1String(", "));
+ }
+ if (s.isEmpty())
+ return s;
+ s.chop(2);
+ s.prepend(QLatin1String("SELECT ")).append(QLatin1String(" FROM ")).append(tableName);
+ break;
+ case WhereStatement:
+ if (preparedStatement) {
+ for (int i = 0; i < rec.count(); ++i) {
+ s.append(prepareIdentifier(rec.fieldName(i), FieldName,this));
+ if (rec.isNull(i))
+ s.append(QLatin1String(" IS NULL"));
+ else
+ s.append(QLatin1String(" = ?"));
+ s.append(QLatin1String(" AND "));
+ }
+ } else {
+ for (i = 0; i < rec.count(); ++i) {
+ s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this));
+ QString val = formatValue(rec.field(i));
+ if (val == QLatin1String("NULL"))
+ s.append(QLatin1String(" IS NULL"));
+ else
+ s.append(QLatin1String(" = ")).append(val);
+ s.append(QLatin1String(" AND "));
+ }
+ }
+ if (!s.isEmpty()) {
+ s.prepend(QLatin1String("WHERE "));
+ s.chop(5); // remove tailing AND
+ }
+ break;
+ case UpdateStatement:
+ s.append(QLatin1String("UPDATE ")).append(tableName).append(
+ QLatin1String(" SET "));
+ for (i = 0; i < rec.count(); ++i) {
+ if (!rec.isGenerated(i))
+ continue;
+ s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this)).append(QLatin1Char('='));
+ if (preparedStatement)
+ s.append(QLatin1Char('?'));
+ else
+ s.append(formatValue(rec.field(i)));
+ s.append(QLatin1String(", "));
+ }
+ if (s.endsWith(QLatin1String(", ")))
+ s.chop(2);
+ else
+ s.clear();
+ break;
+ case DeleteStatement:
+ s.append(QLatin1String("DELETE FROM ")).append(tableName);
+ break;
+ case InsertStatement: {
+ s.append(QLatin1String("INSERT INTO ")).append(tableName).append(QLatin1String(" ("));
+ QString vals;
+ for (i = 0; i < rec.count(); ++i) {
+ if (!rec.isGenerated(i))
+ continue;
+ s.append(prepareIdentifier(rec.fieldName(i), QSqlDriver::FieldName, this)).append(QLatin1String(", "));
+ if (preparedStatement)
+ vals.append(QLatin1Char('?'));
+ else
+ vals.append(formatValue(rec.field(i)));
+ vals.append(QLatin1String(", "));
+ }
+ if (vals.isEmpty()) {
+ s.clear();
+ } else {
+ vals.chop(2); // remove trailing comma
+ s[s.length() - 2] = QLatin1Char(')');
+ s.append(QLatin1String("VALUES (")).append(vals).append(QLatin1Char(')'));
+ }
+ break; }
+ }
+ return s;
+}
+
+/*!
+ Returns a string representation of the \a field value for the
+ database. This is used, for example, when constructing INSERT and
+ UPDATE statements.
+
+ The default implementation returns the value formatted as a string
+ according to the following rules:
+
+ \list
+
+ \i If \a field is character data, the value is returned enclosed
+ in single quotation marks, which is appropriate for many SQL
+ databases. Any embedded single-quote characters are escaped
+ (replaced with two single-quote characters). If \a trimStrings is
+ true (the default is false), all trailing whitespace is trimmed
+ from the field.
+
+ \i If \a field is date/time data, the value is formatted in ISO
+ format and enclosed in single quotation marks. If the date/time
+ data is invalid, "NULL" is returned.
+
+ \i If \a field is \link QByteArray bytearray\endlink data, and the
+ driver can edit binary fields, the value is formatted as a
+ hexadecimal string.
+
+ \i For any other field type, toString() is called on its value
+ and the result of this is returned.
+
+ \endlist
+
+ \sa QVariant::toString()
+
+*/
+QString QSqlDriver::formatValue(const QSqlField &field, bool trimStrings) const
+{
+ const QLatin1String nullTxt("NULL");
+
+ QString r;
+ if (field.isNull())
+ r = nullTxt;
+ else {
+ switch (field.type()) {
+ case QVariant::Int:
+ case QVariant::UInt:
+ if (field.value().type() == QVariant::Bool)
+ r = field.value().toBool() ? QLatin1String("1") : QLatin1String("0");
+ else
+ r = field.value().toString();
+ break;
+#ifndef QT_NO_DATESTRING
+ case QVariant::Date:
+ if (field.value().toDate().isValid())
+ r = QLatin1Char('\'') + field.value().toDate().toString(Qt::ISODate)
+ + QLatin1Char('\'');
+ else
+ r = nullTxt;
+ break;
+ case QVariant::Time:
+ if (field.value().toTime().isValid())
+ r = QLatin1Char('\'') + field.value().toTime().toString(Qt::ISODate)
+ + QLatin1Char('\'');
+ else
+ r = nullTxt;
+ break;
+ case QVariant::DateTime:
+ if (field.value().toDateTime().isValid())
+ r = QLatin1Char('\'') +
+ field.value().toDateTime().toString(Qt::ISODate) + QLatin1Char('\'');
+ else
+ r = nullTxt;
+ break;
+#endif
+ case QVariant::String:
+ case QVariant::Char:
+ {
+ QString result = field.value().toString();
+ if (trimStrings) {
+ int end = result.length();
+ while (end && result.at(end-1).isSpace()) /* skip white space from end */
+ end--;
+ result.truncate(end);
+ }
+ /* escape the "'" character */
+ result.replace(QLatin1Char('\''), QLatin1String("''"));
+ r = QLatin1Char('\'') + result + QLatin1Char('\'');
+ break;
+ }
+ case QVariant::Bool:
+ r = QString::number(field.value().toBool());
+ break;
+ case QVariant::ByteArray : {
+ if (hasFeature(BLOB)) {
+ QByteArray ba = field.value().toByteArray();
+ QString res;
+ static const char hexchars[] = "0123456789abcdef";
+ for (int i = 0; i < ba.size(); ++i) {
+ uchar s = (uchar) ba[i];
+ res += QLatin1Char(hexchars[s >> 4]);
+ res += QLatin1Char(hexchars[s & 0x0f]);
+ }
+ r = QLatin1Char('\'') + res + QLatin1Char('\'');
+ break;
+ }
+ }
+ default:
+ r = field.value().toString();
+ break;
+ }
+ }
+ return r;
+}
+
+/*!
+ Returns the low-level database handle wrapped in a QVariant or an
+ invalid variant if there is no handle.
+
+ \warning Use this with uttermost care and only if you know what you're doing.
+
+ \warning The handle returned here can become a stale pointer if the connection
+ is modified (for example, if you close the connection).
+
+ \warning The handle can be NULL if the connection is not open yet.
+
+ The handle returned here is database-dependent, you should query the type
+ name of the variant before accessing it.
+
+ This example retrieves the handle for a connection to sqlite:
+
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqldriver.cpp 0
+
+ This snippet returns the handle for PostgreSQL or MySQL:
+
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqldriver.cpp 1
+
+ \sa QSqlResult::handle()
+*/
+QVariant QSqlDriver::handle() const
+{
+ return QVariant();
+}
+
+/*!
+ \fn QSqlRecord QSqlDriver::record(const QSqlQuery& query) const
+
+ Use query.record() instead.
+*/
+
+/*!
+ \fn QSqlRecord QSqlDriver::recordInfo(const QString& tablename) const
+
+ Use record() instead.
+*/
+
+/*!
+ \fn QSqlRecord QSqlDriver::recordInfo(const QSqlQuery& query) const
+
+ Use query.record() instead.
+*/
+
+/*!
+ \fn QString QSqlDriver::nullText() const
+
+ sqlStatement() is now used to generate SQL. Use tr("NULL") for example, instead.
+*/
+
+/*!
+ \fn QString QSqlDriver::formatValue(const QSqlField *field, bool trimStrings) const
+
+ Use the other formatValue() overload instead.
+*/
+
+/*!
+ This function is called to subscribe to event notifications from the database.
+ \a name identifies the event notification.
+
+ If successful, return true, otherwise return false.
+
+ The database must be open when this function is called. When the database is closed
+ by calling close() all subscribed event notifications are automatically unsubscribed.
+ Note that calling open() on an already open database may implicitly cause close() to
+ be called, which will cause the driver to unsubscribe from all event notifications.
+
+ When an event notification identified by \a name is posted by the database the
+ notification() signal is emitted.
+
+ \warning Because of binary compatibility constraints, this function is not virtual.
+ If you want to provide event notification support in your own QSqlDriver subclass,
+ reimplement the subscribeToNotificationImplementation() slot in your subclass instead.
+ The subscribeToNotification() function will dynamically detect the slot and call it.
+
+ \since 4.4
+ \sa unsubscribeFromNotification() subscribedToNotifications() QSqlDriver::hasFeature()
+*/
+bool QSqlDriver::subscribeToNotification(const QString &name)
+{
+ bool result;
+ QMetaObject::invokeMethod(const_cast<QSqlDriver *>(this),
+ "subscribeToNotificationImplementation", Qt::DirectConnection,
+ Q_RETURN_ARG(bool, result),
+ Q_ARG(QString, name));
+ return result;
+}
+
+/*!
+ This function is called to unsubscribe from event notifications from the database.
+ \a name identifies the event notification.
+
+ If successful, return true, otherwise return false.
+
+ The database must be open when this function is called. All subscribed event
+ notifications are automatically unsubscribed from when the close() function is called.
+
+ After calling \e this function the notification() signal will no longer be emitted
+ when an event notification identified by \a name is posted by the database.
+
+ \warning Because of binary compatibility constraints, this function is not virtual.
+ If you want to provide event notification support in your own QSqlDriver subclass,
+ reimplement the unsubscribeFromNotificationImplementation() slot in your subclass instead.
+ The unsubscribeFromNotification() function will dynamically detect the slot and call it.
+
+ \since 4.4
+ \sa subscribeToNotification() subscribedToNotifications()
+*/
+bool QSqlDriver::unsubscribeFromNotification(const QString &name)
+{
+ bool result;
+ QMetaObject::invokeMethod(const_cast<QSqlDriver *>(this),
+ "unsubscribeFromNotificationImplementation", Qt::DirectConnection,
+ Q_RETURN_ARG(bool, result),
+ Q_ARG(QString, name));
+ return result;
+}
+
+/*!
+ Returns a list of the names of the event notifications that are currently subscribed to.
+
+ \warning Because of binary compatibility constraints, this function is not virtual.
+ If you want to provide event notification support in your own QSqlDriver subclass,
+ reimplement the subscribedToNotificationsImplementation() slot in your subclass instead.
+ The subscribedToNotifications() function will dynamically detect the slot and call it.
+
+ \since 4.4
+ \sa subscribeToNotification() unsubscribeFromNotification()
+*/
+QStringList QSqlDriver::subscribedToNotifications() const
+{
+ QStringList result;
+ QMetaObject::invokeMethod(const_cast<QSqlDriver *>(this),
+ "subscribedToNotificationsImplementation", Qt::DirectConnection,
+ Q_RETURN_ARG(QStringList, result));
+ return result;
+}
+
+/*!
+ This slot is called to subscribe to event notifications from the database.
+ \a name identifies the event notification.
+
+ If successful, return true, otherwise return false.
+
+ The database must be open when this \e slot is called. When the database is closed
+ by calling close() all subscribed event notifications are automatically unsubscribed.
+ Note that calling open() on an already open database may implicitly cause close() to
+ be called, which will cause the driver to unsubscribe from all event notifications.
+
+ When an event notification identified by \a name is posted by the database the
+ notification() signal is emitted.
+
+ Reimplement this slot to provide your own QSqlDriver subclass with event notification
+ support; because of binary compatibility constraints, the subscribeToNotification()
+ function (introduced in Qt 4.4) is not virtual. Instead, subscribeToNotification()
+ will dynamically detect and call \e this slot. The default implementation does nothing
+ and returns false.
+
+ \since 4.4
+ \sa subscribeToNotification()
+*/
+bool QSqlDriver::subscribeToNotificationImplementation(const QString &name)
+{
+ Q_UNUSED(name);
+ return false;
+}
+
+/*!
+ This slot is called to unsubscribe from event notifications from the database.
+ \a name identifies the event notification.
+
+ If successful, return true, otherwise return false.
+
+ The database must be open when \e this slot is called. All subscribed event
+ notifications are automatically unsubscribed from when the close() function is called.
+
+ After calling \e this slot the notification() signal will no longer be emitted
+ when an event notification identified by \a name is posted by the database.
+
+ Reimplement this slot to provide your own QSqlDriver subclass with event notification
+ support; because of binary compatibility constraints, the unsubscribeFromNotification()
+ function (introduced in Qt 4.4) is not virtual. Instead, unsubscribeFromNotification()
+ will dynamically detect and call \e this slot. The default implementation does nothing
+ and returns false.
+
+ \since 4.4
+ \sa unsubscribeFromNotification()
+*/
+bool QSqlDriver::unsubscribeFromNotificationImplementation(const QString &name)
+{
+ Q_UNUSED(name);
+ return false;
+}
+
+/*!
+ Returns a list of the names of the event notifications that are currently subscribed to.
+
+ Reimplement this slot to provide your own QSqlDriver subclass with event notification
+ support; because of binary compatibility constraints, the subscribedToNotifications()
+ function (introduced in Qt 4.4) is not virtual. Instead, subscribedToNotifications()
+ will dynamically detect and call \e this slot. The default implementation simply
+ returns an empty QStringList.
+
+ \since 4.4
+ \sa subscribedToNotifications()
+*/
+QStringList QSqlDriver::subscribedToNotificationsImplementation() const
+{
+ return QStringList();
+}
+
+/*!
+ \since 4.6
+
+ This slot returns whether \a identifier is escaped according to the database rules.
+ \a identifier can either be a table name or field name, dependent
+ on \a type.
+
+ Because of binary compatibility constraints, isIdentifierEscaped() function
+ (introduced in Qt 4.5) is not virtual. Instead, isIdentifierEscaped() will
+ dynamically detect and call \e this slot. The default implementation
+ assumes the escape/delimiter character is a double quote. Reimplement this
+ slot in your own QSqlDriver if your database engine uses a different
+ delimiter character.
+
+ \sa isIdentifierEscaped()
+ */
+bool QSqlDriver::isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const
+{
+ Q_UNUSED(type);
+ return identifier.size() > 2
+ && identifier.startsWith(QLatin1Char('"')) //left delimited
+ && identifier.endsWith(QLatin1Char('"')); //right delimited
+}
+
+/*!
+ \since 4.6
+
+ This slot returns \a identifier with the leading and trailing delimiters removed,
+ \a identifier can either be a tablename or field name, dependent on \a type.
+ If \a identifier does not have leading and trailing delimiter characters, \a
+ identifier is returned without modification.
+
+ Because of binary compatibility constraints, the stripDelimiters() function
+ (introduced in Qt 4.5) is not virtual. Instead, stripDelimiters() will
+ dynamically detect and call \e this slot. It generally unnecessary
+ to reimplement this slot.
+
+ \sa stripDelimiters()
+ */
+QString QSqlDriver::stripDelimitersImplementation(const QString &identifier, IdentifierType type) const
+{
+ QString ret;
+ if (this->isIdentifierEscaped(identifier, type)) {
+ ret = identifier.mid(1);
+ ret.chop(1);
+ } else {
+ ret = identifier;
+ }
+ return ret;
+}
+
+/*!
+ \since 4.6
+
+ Sets the default numerical precision policy used by queries created
+ by this driver to \a precisionPolicy.
+
+ Note: Setting the default precision policy to \a precisionPolicy
+ doesn't affect any currently active queries.
+
+ \sa QSql::NumericalPrecisionPolicy, numericalPrecisionPolicy(),
+ QSqlQuery::setNumericalPrecisionPolicy(), QSqlQuery::numericalPrecisionPolicy()
+*/
+void QSqlDriver::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy)
+{
+ d_func()->precisionPolicy = precisionPolicy;
+}
+
+/*!
+ \since 4.6
+
+ Returns the current default precision policy for the database connection.
+
+ \sa QSql::NumericalPrecisionPolicy, setNumericalPrecisionPolicy(),
+ QSqlQuery::numericalPrecisionPolicy(), QSqlQuery::setNumericalPrecisionPolicy()
+*/
+QSql::NumericalPrecisionPolicy QSqlDriver::numericalPrecisionPolicy() const
+{
+ return d_func()->precisionPolicy;
+}
+
+QT_END_NAMESPACE
diff --git a/src/sql/kernel/qsqldriver.h b/src/sql/kernel/qsqldriver.h
new file mode 100644
index 0000000000..8adffcf25d
--- /dev/null
+++ b/src/sql/kernel/qsqldriver.h
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQLDRIVER_H
+#define QSQLDRIVER_H
+
+#include <QtCore/qobject.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qstringlist.h>
+#include <QtSql/qsql.h>
+#ifdef QT3_SUPPORT
+#include <QtSql/qsqlquery.h>
+#endif
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sql)
+
+class QSqlDatabase;
+class QSqlDriverPrivate;
+class QSqlError;
+class QSqlField;
+class QSqlIndex;
+class QSqlRecord;
+class QSqlResult;
+class QVariant;
+
+class Q_SQL_EXPORT QSqlDriver : public QObject
+{
+ friend class QSqlDatabase;
+ Q_OBJECT
+ Q_DECLARE_PRIVATE(QSqlDriver)
+
+public:
+ enum DriverFeature { Transactions, QuerySize, BLOB, Unicode, PreparedQueries,
+ NamedPlaceholders, PositionalPlaceholders, LastInsertId,
+ BatchOperations, SimpleLocking, LowPrecisionNumbers,
+ EventNotifications, FinishQuery, MultipleResultSets };
+
+ enum StatementType { WhereStatement, SelectStatement, UpdateStatement,
+ InsertStatement, DeleteStatement };
+
+ enum IdentifierType { FieldName, TableName };
+
+ explicit QSqlDriver(QObject *parent=0);
+ ~QSqlDriver();
+ virtual bool isOpen() const;
+ bool isOpenError() const;
+
+ virtual bool beginTransaction();
+ virtual bool commitTransaction();
+ virtual bool rollbackTransaction();
+ virtual QStringList tables(QSql::TableType tableType) const;
+ virtual QSqlIndex primaryIndex(const QString &tableName) const;
+ virtual QSqlRecord record(const QString &tableName) const;
+#ifdef QT3_SUPPORT
+ inline QT3_SUPPORT QSqlRecord record(const QSqlQuery& query) const
+ { return query.record(); }
+ inline QT3_SUPPORT QSqlRecord recordInfo(const QString& tablename) const
+ { return record(tablename); }
+ inline QT3_SUPPORT QSqlRecord recordInfo(const QSqlQuery& query) const
+ { return query.record(); }
+ inline QT3_SUPPORT QString nullText() const { return QLatin1String("NULL"); }
+ inline QT3_SUPPORT QString formatValue(const QSqlField *field, bool trimStrings = false) const
+ { return field ? formatValue(*field, trimStrings) : QString(); }
+#endif
+ virtual QString formatValue(const QSqlField& field, bool trimStrings = false) const;
+
+ virtual QString escapeIdentifier(const QString &identifier, IdentifierType type) const;
+ virtual QString sqlStatement(StatementType type, const QString &tableName,
+ const QSqlRecord &rec, bool preparedStatement) const;
+
+ QSqlError lastError() const;
+
+ virtual QVariant handle() const;
+ virtual bool hasFeature(DriverFeature f) const = 0;
+ virtual void close() = 0;
+ virtual QSqlResult *createResult() const = 0;
+
+ virtual bool open(const QString& db,
+ const QString& user = QString(),
+ const QString& password = QString(),
+ const QString& host = QString(),
+ int port = -1,
+ const QString& connOpts = QString()) = 0;
+ bool subscribeToNotification(const QString &name); // ### Qt 5: make virtual
+ bool unsubscribeFromNotification(const QString &name); // ### Qt 5: make virtual
+ QStringList subscribedToNotifications() const; // ### Qt 5: make virtual
+
+ bool isIdentifierEscaped(const QString &identifier, IdentifierType type) const; // ### Qt 5: make virtual
+ QString stripDelimiters(const QString &identifier, IdentifierType type) const; // ### Qt 5: make virtual
+
+ void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy);
+ QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
+
+Q_SIGNALS:
+ void notification(const QString &name);
+
+protected:
+ virtual void setOpen(bool o);
+ virtual void setOpenError(bool e);
+ virtual void setLastError(const QSqlError& e);
+
+protected Q_SLOTS:
+ bool subscribeToNotificationImplementation(const QString &name); // ### Qt 5: eliminate, see subscribeToNotification()
+ bool unsubscribeFromNotificationImplementation(const QString &name); // ### Qt 5: eliminate, see unsubscribeFromNotification()
+ QStringList subscribedToNotificationsImplementation() const; // ### Qt 5: eliminate, see subscribedNotifications()
+
+ bool isIdentifierEscapedImplementation(const QString &identifier, IdentifierType type) const; // ### Qt 5: eliminate, see isIdentifierEscaped()
+ QString stripDelimitersImplementation(const QString &identifier, IdentifierType type) const; // ### Qt 5: eliminate, see stripDelimiters()
+
+private:
+ Q_DISABLE_COPY(QSqlDriver)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSQLDRIVER_H
diff --git a/src/sql/kernel/qsqldriverplugin.cpp b/src/sql/kernel/qsqldriverplugin.cpp
new file mode 100644
index 0000000000..b1edfb9d19
--- /dev/null
+++ b/src/sql/kernel/qsqldriverplugin.cpp
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qsqldriverplugin.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSqlDriverPlugin
+ \brief The QSqlDriverPlugin class provides an abstract base for custom QSqlDriver plugins.
+
+ \ingroup plugins
+ \inmodule QtSql
+
+ The SQL driver plugin is a simple plugin interface that makes it
+ easy to create your own SQL driver plugins that can be loaded
+ dynamically by Qt.
+
+ Writing a SQL plugin is achieved by subclassing this base class,
+ reimplementing the pure virtual functions keys() and create(), and
+ exporting the class with the Q_EXPORT_PLUGIN2() macro. See the SQL
+ plugins that come with Qt for example implementations (in the
+ \c{plugins/src/sqldrivers} subdirectory of the source
+ distribution).
+
+ \sa {How to Create Qt Plugins}
+*/
+
+/*!
+ \fn QStringList QSqlDriverPlugin::keys() const
+
+ Returns the list of drivers (keys) this plugin supports.
+
+ These keys are usually the class names of the custom drivers that
+ are implemented in the plugin.
+
+ \sa create()
+*/
+
+/*!
+ \fn QSqlDriver *QSqlDriverPlugin::create(const QString& key)
+
+ Creates and returns a QSqlDriver object for the driver called \a
+ key. The driver key is usually the class name of the required
+ driver. Keys are case sensitive.
+
+ \sa keys()
+*/
+
+/*!
+ Constructs a SQL driver plugin and sets the parent to \a parent.
+ This is invoked automatically by the Q_EXPORT_PLUGIN2() macro.
+*/
+
+QSqlDriverPlugin::QSqlDriverPlugin(QObject *parent)
+ : QObject(parent)
+{
+}
+
+/*!
+ Destroys the SQL driver plugin.
+
+ You never have to call this explicitly. Qt destroys a plugin
+ automatically when it is no longer used.
+*/
+QSqlDriverPlugin::~QSqlDriverPlugin()
+{
+}
+
+QT_END_NAMESPACE
diff --git a/src/sql/kernel/qsqldriverplugin.h b/src/sql/kernel/qsqldriverplugin.h
new file mode 100644
index 0000000000..4783a211b8
--- /dev/null
+++ b/src/sql/kernel/qsqldriverplugin.h
@@ -0,0 +1,81 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQLDRIVERPLUGIN_H
+#define QSQLDRIVERPLUGIN_H
+
+#include <QtCore/qplugin.h>
+#include <QtCore/qfactoryinterface.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sql)
+
+class QSqlDriver;
+
+struct Q_SQL_EXPORT QSqlDriverFactoryInterface : public QFactoryInterface
+{
+ virtual QSqlDriver *create(const QString &name) = 0;
+};
+
+#define QSqlDriverFactoryInterface_iid "com.trolltech.Qt.QSqlDriverFactoryInterface"
+Q_DECLARE_INTERFACE(QSqlDriverFactoryInterface, QSqlDriverFactoryInterface_iid)
+
+class Q_SQL_EXPORT QSqlDriverPlugin : public QObject, public QSqlDriverFactoryInterface
+{
+ Q_OBJECT
+ Q_INTERFACES(QSqlDriverFactoryInterface:QFactoryInterface)
+public:
+ explicit QSqlDriverPlugin(QObject *parent = 0);
+ ~QSqlDriverPlugin();
+
+ virtual QStringList keys() const = 0;
+ virtual QSqlDriver *create(const QString &key) = 0;
+
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSQLDRIVERPLUGIN_H
diff --git a/src/sql/kernel/qsqlerror.cpp b/src/sql/kernel/qsqlerror.cpp
new file mode 100644
index 0000000000..526d32e452
--- /dev/null
+++ b/src/sql/kernel/qsqlerror.cpp
@@ -0,0 +1,253 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qsqlerror.h"
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QSqlError &s)
+{
+ dbg.nospace() << "QSqlError(" << s.number() << ", " << s.driverText() <<
+ ", " << s.databaseText() << ')';
+ return dbg.space();
+}
+#endif
+
+/*!
+ \class QSqlError
+ \brief The QSqlError class provides SQL database error information.
+
+ \ingroup database
+ \inmodule QtSql
+
+ A QSqlError object can provide database-specific error data,
+ including the driverText() and databaseText() messages (or both
+ concatenated together as text()), and the error number() and
+ type(). The functions all have setters so that you can create and
+ return QSqlError objects from your own classes, for example from
+ your own SQL drivers.
+
+ \sa QSqlDatabase::lastError(), QSqlQuery::lastError()
+*/
+
+/*!
+ \enum QSqlError::ErrorType
+
+ This enum type describes the context in which the error occurred, e.g., a connection error, a statement error, etc.
+
+ \value NoError No error occurred.
+ \value ConnectionError Connection error.
+ \value StatementError SQL statement syntax error.
+ \value TransactionError Transaction failed error.
+ \value UnknownError Unknown error.
+
+ \omitvalue None
+ \omitvalue Connection
+ \omitvalue Statement
+ \omitvalue Transaction
+ \omitvalue Unknown
+*/
+
+/*!
+ Constructs an error containing the driver error text \a
+ driverText, the database-specific error text \a databaseText, the
+ type \a type and the optional error number \a number.
+*/
+
+QSqlError::QSqlError(const QString& driverText, const QString& databaseText, ErrorType type,
+ int number)
+ : driverError(driverText), databaseError(databaseText), errorType(type), errorNumber(number)
+{
+}
+
+/*!
+ Creates a copy of \a other.
+*/
+QSqlError::QSqlError(const QSqlError& other)
+ : driverError(other.driverError), databaseError(other.databaseError),
+ errorType(other.errorType),
+ errorNumber(other.errorNumber)
+{
+}
+
+/*!
+ Assigns the \a other error's values to this error.
+*/
+
+QSqlError& QSqlError::operator=(const QSqlError& other)
+{
+ driverError = other.driverError;
+ databaseError = other.databaseError;
+ errorType = other.errorType;
+ errorNumber = other.errorNumber;
+ return *this;
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QSqlError::~QSqlError()
+{
+}
+
+/*!
+ Returns the text of the error as reported by the driver. This may
+ contain database-specific descriptions. It may also be empty.
+
+ \sa setDriverText() databaseText() text()
+*/
+QString QSqlError::driverText() const
+{
+ return driverError;
+}
+
+/*!
+ Sets the driver error text to the value of \a driverText.
+
+ \sa driverText() setDatabaseText() text()
+*/
+
+void QSqlError::setDriverText(const QString& driverText)
+{
+ driverError = driverText;
+}
+
+/*!
+ Returns the text of the error as reported by the database. This
+ may contain database-specific descriptions; it may be empty.
+
+ \sa setDatabaseText() driverText() text()
+*/
+
+QString QSqlError::databaseText() const
+{
+ return databaseError;
+}
+
+/*!
+ Sets the database error text to the value of \a databaseText.
+
+ \sa databaseText() setDriverText() text()
+*/
+
+void QSqlError::setDatabaseText(const QString& databaseText)
+{
+ databaseError = databaseText;
+}
+
+/*!
+ Returns the error type, or -1 if the type cannot be determined.
+
+ \sa setType()
+*/
+
+QSqlError::ErrorType QSqlError::type() const
+{
+ return errorType;
+}
+
+/*!
+ Sets the error type to the value of \a type.
+
+ \sa type()
+*/
+
+void QSqlError::setType(ErrorType type)
+{
+ errorType = type;
+}
+
+/*!
+ Returns the database-specific error number, or -1 if it cannot be
+ determined.
+
+ \sa setNumber()
+*/
+
+int QSqlError::number() const
+{
+ return errorNumber;
+}
+
+/*!
+ Sets the database-specific error number to \a number.
+
+ \sa number()
+*/
+
+void QSqlError::setNumber(int number)
+{
+ errorNumber = number;
+}
+
+/*!
+ This is a convenience function that returns databaseText() and
+ driverText() concatenated into a single string.
+
+ \sa driverText() databaseText()
+*/
+
+QString QSqlError::text() const
+{
+ QString result = databaseError;
+ if (!databaseError.endsWith(QLatin1String("\n")))
+ result += QLatin1Char(' ');
+ result += driverError;
+ return result;
+}
+
+/*!
+ Returns true if an error is set, otherwise false.
+
+ Example:
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqlerror.cpp 0
+
+ \sa type()
+*/
+bool QSqlError::isValid() const
+{
+ return errorType != NoError;
+}
+
+QT_END_NAMESPACE
diff --git a/src/sql/kernel/qsqlerror.h b/src/sql/kernel/qsqlerror.h
new file mode 100644
index 0000000000..5375e94127
--- /dev/null
+++ b/src/sql/kernel/qsqlerror.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQLERROR_H
+#define QSQLERROR_H
+
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sql)
+
+class Q_SQL_EXPORT QSqlError
+{
+public:
+ enum ErrorType {
+ NoError,
+ ConnectionError,
+ StatementError,
+ TransactionError,
+ UnknownError
+#ifdef QT3_SUPPORT
+ , None = NoError,
+ Connection = ConnectionError,
+ Statement = StatementError,
+ Transaction = TransactionError,
+ Unknown = UnknownError
+#endif
+ };
+ QSqlError( const QString& driverText = QString(),
+ const QString& databaseText = QString(),
+ ErrorType type = NoError,
+ int number = -1);
+ QSqlError(const QSqlError& other);
+ QSqlError& operator=(const QSqlError& other);
+ ~QSqlError();
+
+ QString driverText() const;
+ void setDriverText(const QString& driverText);
+ QString databaseText() const;
+ void setDatabaseText(const QString& databaseText);
+ ErrorType type() const;
+ void setType(ErrorType type);
+ int number() const;
+ void setNumber(int number);
+ QString text() const;
+ bool isValid() const;
+
+private:
+ QString driverError;
+ QString databaseError;
+ ErrorType errorType;
+ int errorNumber;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_SQL_EXPORT QDebug operator<<(QDebug, const QSqlError &);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSQLERROR_H
diff --git a/src/sql/kernel/qsqlfield.cpp b/src/sql/kernel/qsqlfield.cpp
new file mode 100644
index 0000000000..b7e58b79d9
--- /dev/null
+++ b/src/sql/kernel/qsqlfield.cpp
@@ -0,0 +1,560 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qsqlfield.h"
+#include "qatomic.h"
+#include "qdebug.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSqlFieldPrivate
+{
+public:
+ QSqlFieldPrivate(const QString &name,
+ QVariant::Type type) :
+ ref(1), nm(name), ro(false), type(type), req(QSqlField::Unknown),
+ len(-1), prec(-1), tp(-1), gen(true), autoval(false)
+ {
+ }
+
+ QSqlFieldPrivate(const QSqlFieldPrivate &other)
+ : ref(1),
+ nm(other.nm),
+ ro(other.ro),
+ type(other.type),
+ req(other.req),
+ len(other.len),
+ prec(other.prec),
+ def(other.def),
+ tp(other.tp),
+ gen(other.gen),
+ autoval(other.autoval)
+ {}
+
+ bool operator==(const QSqlFieldPrivate& other) const
+ {
+ return (nm == other.nm
+ && ro == other.ro
+ && type == other.type
+ && req == other.req
+ && len == other.len
+ && prec == other.prec
+ && def == other.def
+ && gen == other.gen
+ && autoval == other.autoval);
+ }
+
+ QAtomicInt ref;
+ QString nm;
+ uint ro: 1;
+ QVariant::Type type;
+ QSqlField::RequiredStatus req;
+ int len;
+ int prec;
+ QVariant def;
+ int tp;
+ uint gen: 1;
+ uint autoval: 1;
+};
+
+
+/*!
+ \class QSqlField
+ \brief The QSqlField class manipulates the fields in SQL database tables
+ and views.
+
+ \ingroup database
+ \ingroup shared
+ \inmodule QtSql
+
+ QSqlField represents the characteristics of a single column in a
+ database table or view, such as the data type and column name. A
+ field also contains the value of the database column, which can be
+ viewed or changed.
+
+ Field data values are stored as QVariants. Using an incompatible
+ type is not permitted. For example:
+
+ \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 2
+
+ However, the field will attempt to cast certain data types to the
+ field data type where possible:
+
+ \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 3
+
+ QSqlField objects are rarely created explicitly in application
+ code. They are usually accessed indirectly through \l{QSqlRecord}s
+ that already contain a list of fields. For example:
+
+ \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 4
+ \dots
+ \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 5
+ \snippet doc/src/snippets/sqldatabase/sqldatabase.cpp 6
+
+ A QSqlField object can provide some meta-data about the field, for
+ example, its name(), variant type(), length(), precision(),
+ defaultValue(), typeID(), and its requiredStatus(),
+ isGenerated() and isReadOnly(). The field's data can be
+ checked to see if it isNull(), and its value() retrieved. When
+ editing the data can be set with setValue() or set to NULL with
+ clear().
+
+ \sa QSqlRecord
+*/
+
+/*!
+ \enum QSqlField::RequiredStatus
+
+ Specifies whether the field is required or optional.
+
+ \value Required The field must be specified when inserting records.
+ \value Optional The fields doesn't have to be specified when inserting records.
+ \value Unknown The database driver couldn't determine whether the field is required or
+ optional.
+
+ \sa requiredStatus()
+*/
+
+/*!
+ Constructs an empty field called \a fieldName of variant type \a
+ type.
+
+ \sa setRequiredStatus() setLength() setPrecision() setDefaultValue() setGenerated() setReadOnly()
+*/
+QSqlField::QSqlField(const QString& fieldName, QVariant::Type type)
+{
+ d = new QSqlFieldPrivate(fieldName, type);
+ val = QVariant(type);
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+
+QSqlField::QSqlField(const QSqlField& other)
+{
+ d = other.d;
+ d->ref.ref();
+ val = other.val;
+}
+
+/*!
+ Sets the field equal to \a other.
+*/
+
+QSqlField& QSqlField::operator=(const QSqlField& other)
+{
+ qAtomicAssign(d, other.d);
+ val = other.val;
+ return *this;
+}
+
+
+/*! \fn bool QSqlField::operator!=(const QSqlField &other) const
+ Returns true if the field is unequal to \a other; otherwise returns
+ false.
+*/
+
+/*!
+ Returns true if the field is equal to \a other; otherwise returns
+ false.
+*/
+bool QSqlField::operator==(const QSqlField& other) const
+{
+ return ((d == other.d || *d == *other.d)
+ && val == other.val);
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QSqlField::~QSqlField()
+{
+ if (!d->ref.deref())
+ delete d;
+}
+
+/*!
+ Sets the required status of this field to \a required.
+
+ \sa requiredStatus() setType() setLength() setPrecision() setDefaultValue() setGenerated() setReadOnly()
+*/
+void QSqlField::setRequiredStatus(RequiredStatus required)
+{
+ detach();
+ d->req = required;
+}
+
+/*! \fn void QSqlField::setRequired(bool required)
+
+ Sets the required status of this field to \l Required if \a
+ required is true; otherwise sets it to \l Optional.
+
+ \sa setRequiredStatus(), requiredStatus()
+*/
+
+/*!
+ Sets the field's length to \a fieldLength. For strings this is the
+ maximum number of characters the string can hold; the meaning
+ varies for other types.
+
+ \sa length() setType() setRequiredStatus() setPrecision() setDefaultValue() setGenerated() setReadOnly()
+*/
+void QSqlField::setLength(int fieldLength)
+{
+ detach();
+ d->len = fieldLength;
+}
+
+/*!
+ Sets the field's \a precision. This only affects numeric fields.
+
+ \sa precision() setType() setRequiredStatus() setLength() setDefaultValue() setGenerated() setReadOnly()
+*/
+void QSqlField::setPrecision(int precision)
+{
+ detach();
+ d->prec = precision;
+}
+
+/*!
+ Sets the default value used for this field to \a value.
+
+ \sa defaultValue() value() setType() setRequiredStatus() setLength() setPrecision() setGenerated() setReadOnly()
+*/
+void QSqlField::setDefaultValue(const QVariant &value)
+{
+ detach();
+ d->def = value;
+}
+
+/*!
+ \internal
+*/
+void QSqlField::setSqlType(int type)
+{
+ detach();
+ d->tp = type;
+}
+
+/*!
+ Sets the generated state. If \a gen is false, no SQL will
+ be generated for this field; otherwise, Qt classes such as
+ QSqlQueryModel and QSqlTableModel will generate SQL for this
+ field.
+
+ \sa isGenerated() setType() setRequiredStatus() setLength() setPrecision() setDefaultValue() setReadOnly()
+*/
+void QSqlField::setGenerated(bool gen)
+{
+ detach();
+ d->gen = gen;
+}
+
+
+/*!
+ Sets the value of the field to \a value. If the field is read-only
+ (isReadOnly() returns true), nothing happens.
+
+ If the data type of \a value differs from the field's current
+ data type, an attempt is made to cast it to the proper type. This
+ preserves the data type of the field in the case of assignment,
+ e.g. a QString to an integer data type.
+
+ To set the value to NULL, use clear().
+
+ \sa value() isReadOnly() defaultValue()
+*/
+
+void QSqlField::setValue(const QVariant& value)
+{
+ if (isReadOnly())
+ return;
+ val = value;
+}
+
+/*!
+ Clears the value of the field and sets it to NULL.
+ If the field is read-only, nothing happens.
+
+ \sa setValue() isReadOnly() requiredStatus()
+*/
+
+void QSqlField::clear()
+{
+ if (isReadOnly())
+ return;
+ val = QVariant(type());
+}
+
+/*!
+ Sets the name of the field to \a name.
+
+ \sa name()
+*/
+
+void QSqlField::setName(const QString& name)
+{
+ detach();
+ d->nm = name;
+}
+
+/*!
+ Sets the read only flag of the field's value to \a readOnly. A
+ read-only field cannot have its value set with setValue() and
+ cannot be cleared to NULL with clear().
+*/
+void QSqlField::setReadOnly(bool readOnly)
+{
+ detach();
+ d->ro = readOnly;
+}
+
+/*!
+ \fn QVariant QSqlField::value() const
+
+ Returns the value of the field as a QVariant.
+
+ Use isNull() to check if the field's value is NULL.
+*/
+
+/*!
+ Returns the name of the field.
+
+ \sa setName()
+*/
+QString QSqlField::name() const
+{
+ return d->nm;
+}
+
+/*!
+ Returns the field's type as stored in the database.
+ Note that the actual value might have a different type,
+ Numerical values that are too large to store in a long
+ int or double are usually stored as strings to prevent
+ precision loss.
+
+ \sa setType()
+*/
+QVariant::Type QSqlField::type() const
+{
+ return d->type;
+}
+
+/*!
+ Set's the field's variant type to \a type.
+
+ \sa type() setRequiredStatus() setLength() setPrecision() setDefaultValue() setGenerated() setReadOnly()
+*/
+void QSqlField::setType(QVariant::Type type)
+{
+ detach();
+ d->type = type;
+ if (!val.isValid())
+ val = QVariant(type);
+}
+
+
+/*!
+ Returns true if the field's value is read-only; otherwise returns
+ false.
+
+ \sa setReadOnly() type() requiredStatus() length() precision() defaultValue() isGenerated()
+*/
+bool QSqlField::isReadOnly() const
+{ return d->ro; }
+
+/*!
+ Returns true if the field's value is NULL; otherwise returns
+ false.
+
+ \sa value()
+*/
+bool QSqlField::isNull() const
+{ return val.isNull(); }
+
+/*! \internal
+*/
+void QSqlField::detach()
+{
+ qAtomicDetach(d);
+}
+
+/*!
+ Returns true if this is a required field; otherwise returns false.
+ An \c INSERT will fail if a required field does not have a value.
+
+ \sa setRequiredStatus() type() length() precision() defaultValue() isGenerated()
+*/
+QSqlField::RequiredStatus QSqlField::requiredStatus() const
+{
+ return d->req;
+}
+
+/*!
+ Returns the field's length.
+
+ If the returned value is negative, it means that the information
+ is not available from the database.
+
+ \sa setLength() type() requiredStatus() precision() defaultValue() isGenerated()
+*/
+int QSqlField::length() const
+{
+ return d->len;
+}
+
+/*!
+ Returns the field's precision; this is only meaningful for numeric
+ types.
+
+ If the returned value is negative, it means that the information
+ is not available from the database.
+
+ \sa setPrecision() type() requiredStatus() length() defaultValue() isGenerated()
+*/
+int QSqlField::precision() const
+{
+ return d->prec;
+}
+
+/*!
+ Returns the field's default value (which may be NULL).
+
+ \sa setDefaultValue() type() requiredStatus() length() precision() isGenerated()
+*/
+QVariant QSqlField::defaultValue() const
+{
+ return d->def;
+}
+
+/*!
+ \internal
+
+ Returns the type ID for the field.
+
+ If the returned value is negative, it means that the information
+ is not available from the database.
+*/
+int QSqlField::typeID() const
+{
+ return d->tp;
+}
+
+/*!
+ Returns true if the field is generated; otherwise returns
+ false.
+
+ \sa setGenerated() type() requiredStatus() length() precision() defaultValue()
+*/
+bool QSqlField::isGenerated() const
+{
+ return d->gen;
+}
+
+/*!
+ Returns true if the field's variant type is valid; otherwise
+ returns false.
+*/
+bool QSqlField::isValid() const
+{
+ return d->type != QVariant::Invalid;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QSqlField &f)
+{
+#ifndef Q_BROKEN_DEBUG_STREAM
+ dbg.nospace() << "QSqlField(" << f.name() << ", " << QVariant::typeToName(f.type());
+ if (f.length() >= 0)
+ dbg.nospace() << ", length: " << f.length();
+ if (f.precision() >= 0)
+ dbg.nospace() << ", precision: " << f.precision();
+ if (f.requiredStatus() != QSqlField::Unknown)
+ dbg.nospace() << ", required: "
+ << (f.requiredStatus() == QSqlField::Required ? "yes" : "no");
+ dbg.nospace() << ", generated: " << (f.isGenerated() ? "yes" : "no");
+ if (f.typeID() >= 0)
+ dbg.nospace() << ", typeID: " << f.typeID();
+ if (!f.defaultValue().isNull())
+ dbg.nospace() << ", auto-value: \"" << f.defaultValue() << '\"';
+ dbg.nospace() << ')';
+ return dbg.space();
+#else
+ qWarning("This compiler doesn't support streaming QSqlField to QDebug");
+ return dbg;
+ Q_UNUSED(f);
+#endif
+}
+#endif
+
+/*!
+ \fn void QSqlField::setNull()
+
+ Use clear() instead.
+*/
+
+/*!
+ Returns true if the value is auto-generated by the database,
+ for example auto-increment primary key values.
+
+ \sa setAutoValue()
+*/
+bool QSqlField::isAutoValue() const
+{
+ return d->autoval;
+}
+
+/*!
+ Marks the field as an auto-generated value if \a autoVal
+ is true.
+
+ \sa isAutoValue()
+ */
+void QSqlField::setAutoValue(bool autoVal)
+{
+ detach();
+ d->autoval = autoVal;
+}
+
+QT_END_NAMESPACE
diff --git a/src/sql/kernel/qsqlfield.h b/src/sql/kernel/qsqlfield.h
new file mode 100644
index 0000000000..68d506d8cd
--- /dev/null
+++ b/src/sql/kernel/qsqlfield.h
@@ -0,0 +1,119 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQLFIELD_H
+#define QSQLFIELD_H
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sql)
+
+class QSqlFieldPrivate;
+
+class Q_SQL_EXPORT QSqlField
+{
+public:
+ enum RequiredStatus { Unknown = -1, Optional = 0, Required = 1 };
+
+ QSqlField(const QString& fieldName = QString(),
+ QVariant::Type type = QVariant::Invalid);
+
+ QSqlField(const QSqlField& other);
+ QSqlField& operator=(const QSqlField& other);
+ bool operator==(const QSqlField& other) const;
+ inline bool operator!=(const QSqlField &other) const { return !operator==(other); }
+ ~QSqlField();
+
+ void setValue(const QVariant& value);
+ inline QVariant value() const
+ { return val; }
+ void setName(const QString& name);
+ QString name() const;
+ bool isNull() const;
+ void setReadOnly(bool readOnly);
+ bool isReadOnly() const;
+ void clear();
+ QVariant::Type type() const;
+ bool isAutoValue() const;
+
+ void setType(QVariant::Type type);
+ void setRequiredStatus(RequiredStatus status);
+ inline void setRequired(bool required)
+ { setRequiredStatus(required ? Required : Optional); }
+ void setLength(int fieldLength);
+ void setPrecision(int precision);
+ void setDefaultValue(const QVariant &value);
+ void setSqlType(int type);
+ void setGenerated(bool gen);
+ void setAutoValue(bool autoVal);
+
+ RequiredStatus requiredStatus() const;
+ int length() const;
+ int precision() const;
+ QVariant defaultValue() const;
+ int typeID() const;
+ bool isGenerated() const;
+ bool isValid() const;
+
+#ifdef QT3_SUPPORT
+ inline QT3_SUPPORT void setNull() { clear(); }
+#endif
+
+private:
+ void detach();
+ QVariant val;
+ QSqlFieldPrivate* d;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_SQL_EXPORT QDebug operator<<(QDebug, const QSqlField &);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSQLFIELD_H
diff --git a/src/sql/kernel/qsqlindex.cpp b/src/sql/kernel/qsqlindex.cpp
new file mode 100644
index 0000000000..63158c6c29
--- /dev/null
+++ b/src/sql/kernel/qsqlindex.cpp
@@ -0,0 +1,256 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qsqlindex.h"
+
+#include "qsqlfield.h"
+#include "qstringlist.h"
+
+QT_BEGIN_NAMESPACE
+
+/*!
+ \class QSqlIndex
+ \brief The QSqlIndex class provides functions to manipulate and
+ describe database indexes.
+
+ \ingroup database
+ \inmodule QtSql
+
+ An \e index refers to a single table or view in a database.
+ Information about the fields that comprise the index can be used
+ to generate SQL statements.
+*/
+
+/*!
+ Constructs an empty index using the cursor name \a cursorname and
+ index name \a name.
+*/
+
+QSqlIndex::QSqlIndex(const QString& cursorname, const QString& name)
+ : cursor(cursorname), nm(name)
+{
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+
+QSqlIndex::QSqlIndex(const QSqlIndex& other)
+ : QSqlRecord(other), cursor(other.cursor), nm(other.nm), sorts(other.sorts)
+{
+}
+
+/*!
+ Sets the index equal to \a other.
+*/
+
+QSqlIndex& QSqlIndex::operator=(const QSqlIndex& other)
+{
+ cursor = other.cursor;
+ nm = other.nm;
+ sorts = other.sorts;
+ QSqlRecord::operator=(other);
+ return *this;
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QSqlIndex::~QSqlIndex()
+{
+
+}
+
+/*!
+ Sets the name of the index to \a name.
+*/
+
+void QSqlIndex::setName(const QString& name)
+{
+ nm = name;
+}
+
+/*!
+ \fn QString QSqlIndex::name() const
+
+ Returns the name of the index.
+*/
+
+/*!
+ Appends the field \a field to the list of indexed fields. The
+ field is appended with an ascending sort order.
+*/
+
+void QSqlIndex::append(const QSqlField& field)
+{
+ append(field, false);
+}
+
+/*!
+ \overload
+
+ Appends the field \a field to the list of indexed fields. The
+ field is appended with an ascending sort order, unless \a desc is
+ true.
+*/
+
+void QSqlIndex::append(const QSqlField& field, bool desc)
+{
+ sorts.append(desc);
+ QSqlRecord::append(field);
+}
+
+
+/*!
+ Returns true if field \a i in the index is sorted in descending
+ order; otherwise returns false.
+*/
+
+bool QSqlIndex::isDescending(int i) const
+{
+ if (i >= 0 && i < sorts.size())
+ return sorts[i];
+ return false;
+}
+
+/*!
+ If \a desc is true, field \a i is sorted in descending order.
+ Otherwise, field \a i is sorted in ascending order (the default).
+ If the field does not exist, nothing happens.
+*/
+
+void QSqlIndex::setDescending(int i, bool desc)
+{
+ if (i >= 0 && i < sorts.size())
+ sorts[i] = desc;
+}
+
+#ifdef QT3_SUPPORT
+
+/*!
+ Returns a comma-separated list of all the index's field names as a
+ string. This string is suitable, for example, for generating a
+ SQL SELECT statement. Only generated fields are included in the
+ list (see \l{isGenerated()}). If a \a prefix is specified, e.g. a
+ table name, it is prepended before all field names in the form:
+
+ "\a{prefix}.<fieldname>"
+
+ If \a sep is specified, each field is separated by \a sep. If \a
+ verbose is true (the default), each field contains a suffix
+ indicating an ASCending or DESCending sort order.
+*/
+
+QString QSqlIndex::toString(const QString& prefix, const QString& sep, bool verbose) const
+{
+ QString s;
+ bool comma = false;
+ for (int i = 0; i < count(); ++i) {
+ if(comma)
+ s += sep + QLatin1Char(' ');
+ s += createField(i, prefix, verbose);
+ comma = true;
+ }
+ return s;
+}
+
+/*!
+ Returns a list of all the index's field names. Only generated
+ fields are included in the list (see \l{isGenerated()}). If a \a
+ prefix is specified, e.g. a table name, all fields are prefixed in
+ the form:
+
+ "\a{prefix}.<fieldname>"
+
+ If \a verbose is true (the default), each field contains a suffix
+ indicating an ASCending or DESCending sort order.
+
+ Note that if you want to iterate over the list, you should iterate
+ over a copy, e.g.
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqlindex.cpp 0
+
+*/
+QStringList QSqlIndex::toStringList(const QString& prefix, bool verbose) const
+{
+ QStringList s;
+ for (int i = 0; i < count(); ++i)
+ s += createField(i, prefix, verbose);
+ return s;
+}
+#endif
+
+/*! \internal
+
+ Creates a string representing the field number \a i using prefix \a
+ prefix. If \a verbose is true, ASC or DESC is included in the field
+ description if the field is sorted in ASCending or DESCending order.
+*/
+
+QString QSqlIndex::createField(int i, const QString& prefix, bool verbose) const
+{
+ QString f;
+ if (!prefix.isEmpty())
+ f += prefix + QLatin1Char('.');
+ f += field(i).name();
+ if (verbose)
+ f += QLatin1Char(' ') + QString((isDescending(i)
+ ? QLatin1String("DESC") : QLatin1String("ASC")));
+ return f;
+}
+
+/*!
+ \fn QString QSqlIndex::cursorName() const
+
+ Returns the name of the cursor which the index is associated with.
+*/
+
+
+/*!
+ Sets the name of the cursor that the index is associated with to
+ \a cursorName.
+*/
+void QSqlIndex::setCursorName(const QString& cursorName)
+{
+ cursor = cursorName;
+}
+
+QT_END_NAMESPACE
diff --git a/src/sql/kernel/qsqlindex.h b/src/sql/kernel/qsqlindex.h
new file mode 100644
index 0000000000..df43a320f4
--- /dev/null
+++ b/src/sql/kernel/qsqlindex.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQLINDEX_H
+#define QSQLINDEX_H
+
+#include <QtSql/qsqlrecord.h>
+#include <QtCore/qstring.h>
+#include <QtCore/qlist.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sql)
+
+class Q_SQL_EXPORT QSqlIndex : public QSqlRecord
+{
+public:
+ QSqlIndex(const QString &cursorName = QString(), const QString &name = QString());
+ QSqlIndex(const QSqlIndex &other);
+ ~QSqlIndex();
+ QSqlIndex &operator=(const QSqlIndex &other);
+ void setCursorName(const QString &cursorName);
+ inline QString cursorName() const { return cursor; }
+ void setName(const QString& name);
+ inline QString name() const { return nm; }
+
+ void append(const QSqlField &field);
+ void append(const QSqlField &field, bool desc);
+
+ bool isDescending(int i) const;
+ void setDescending(int i, bool desc);
+
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT QString toString(const QString &prefix = QString(),
+ const QString &sep = QLatin1String(","),
+ bool verbose = true) const;
+ QT3_SUPPORT QStringList toStringList(const QString& prefix = QString(),
+ bool verbose = true) const;
+#endif
+
+private:
+ QString createField(int i, const QString& prefix, bool verbose) const;
+ QString cursor;
+ QString nm;
+ QList<bool> sorts;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSQLINDEX_H
diff --git a/src/sql/kernel/qsqlnulldriver_p.h b/src/sql/kernel/qsqlnulldriver_p.h
new file mode 100644
index 0000000000..ca1f516f29
--- /dev/null
+++ b/src/sql/kernel/qsqlnulldriver_p.h
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQLNULLDRIVER_P_H
+#define QSQLNULLDRIVER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the Qt API. This header file may
+// change from version to version without notice, or even be
+// removed.
+//
+// We mean it.
+//
+
+#include "QtCore/qvariant.h"
+#include "QtSql/qsqldriver.h"
+#include "QtSql/qsqlerror.h"
+#include "QtSql/qsqlresult.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSqlNullResult : public QSqlResult
+{
+public:
+ inline explicit QSqlNullResult(const QSqlDriver* d): QSqlResult(d)
+ { QSqlResult::setLastError(
+ QSqlError(QLatin1String("Driver not loaded"), QLatin1String("Driver not loaded"), QSqlError::ConnectionError)); }
+protected:
+ inline QVariant data(int) { return QVariant(); }
+ inline bool reset (const QString&) { return false; }
+ inline bool fetch(int) { return false; }
+ inline bool fetchFirst() { return false; }
+ inline bool fetchLast() { return false; }
+ inline bool isNull(int) { return false; }
+ inline int size() { return -1; }
+ inline int numRowsAffected() { return 0; }
+
+ inline void setAt(int) {}
+ inline void setActive(bool) {}
+ inline void setLastError(const QSqlError&) {}
+ inline void setQuery(const QString&) {}
+ inline void setSelect(bool) {}
+ inline void setForwardOnly(bool) {}
+
+ inline bool exec() { return false; }
+ inline bool prepare(const QString&) { return false; }
+ inline bool savePrepare(const QString&) { return false; }
+ inline void bindValue(int, const QVariant&, QSql::ParamType) {}
+ inline void bindValue(const QString&, const QVariant&, QSql::ParamType) {}
+};
+
+class QSqlNullDriver : public QSqlDriver
+{
+public:
+ inline QSqlNullDriver(): QSqlDriver()
+ { QSqlDriver::setLastError(
+ QSqlError(QLatin1String("Driver not loaded"), QLatin1String("Driver not loaded"), QSqlError::ConnectionError)); }
+ inline bool hasFeature(DriverFeature) const { return false; }
+ inline bool open(const QString &, const QString & , const QString & ,
+ const QString &, int, const QString&)
+ { return false; }
+ inline void close() {}
+ inline QSqlResult *createResult() const { return new QSqlNullResult(this); }
+
+protected:
+ inline void setOpen(bool) {}
+ inline void setOpenError(bool) {}
+ inline void setLastError(const QSqlError&) {}
+};
+
+QT_END_NAMESPACE
+
+#endif // QSQLNULLDRIVER_P_H
diff --git a/src/sql/kernel/qsqlquery.cpp b/src/sql/kernel/qsqlquery.cpp
new file mode 100644
index 0000000000..3cdc8b147f
--- /dev/null
+++ b/src/sql/kernel/qsqlquery.cpp
@@ -0,0 +1,1236 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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, or is invalid, 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.
+ If \a db is invalid, the application's default database will be used.
+
+ \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.
+
+ \note Calling setForwardOnly after execution of the query will result
+ in unexpected results at best, and crashes at worst.
+
+ \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.
+ In this case, sufficient space must be pre-allocated to store
+ the result into.
+
+ To bind a NULL value, use a null QVariant; for example, use
+ \c {QVariant(QVariant::String)} if you are binding a string.
+
+ Values cannot be bound to multiple locations in the query, eg:
+ \code
+ INSERT INTO testtable (id, name, samename) VALUES (:id, :name, :name)
+ \endcode
+ Binding to name will bind to the first :name, but not the second.
+
+ \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
diff --git a/src/sql/kernel/qsqlquery.h b/src/sql/kernel/qsqlquery.h
new file mode 100644
index 0000000000..4c547c4a32
--- /dev/null
+++ b/src/sql/kernel/qsqlquery.h
@@ -0,0 +1,130 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQLQUERY_H
+#define QSQLQUERY_H
+
+#include <QtSql/qsql.h>
+#include <QtSql/qsqldatabase.h>
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sql)
+
+class QVariant;
+class QSqlDriver;
+class QSqlError;
+class QSqlResult;
+class QSqlRecord;
+template <class Key, class T> class QMap;
+class QSqlQueryPrivate;
+
+class Q_SQL_EXPORT QSqlQuery
+{
+public:
+ QSqlQuery(QSqlResult *r);
+ QSqlQuery(const QString& query = QString(), QSqlDatabase db = QSqlDatabase());
+ explicit QSqlQuery(QSqlDatabase db);
+ QSqlQuery(const QSqlQuery& other);
+ QSqlQuery& operator=(const QSqlQuery& other);
+ ~QSqlQuery();
+
+ bool isValid() const;
+ bool isActive() const;
+ bool isNull(int field) const;
+ int at() const;
+ QString lastQuery() const;
+ int numRowsAffected() const;
+ QSqlError lastError() const;
+ bool isSelect() const;
+ int size() const;
+ const QSqlDriver* driver() const;
+ const QSqlResult* result() const;
+ bool isForwardOnly() const;
+ QSqlRecord record() const;
+
+ void setForwardOnly(bool forward);
+ bool exec(const QString& query);
+ QVariant value(int i) const;
+
+ void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy precisionPolicy);
+ QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
+
+ bool seek(int i, bool relative = false);
+ bool next();
+ bool previous();
+#ifdef QT3_SUPPORT
+ inline QT3_SUPPORT bool prev() { return previous(); }
+#endif
+ bool first();
+ bool last();
+
+ void clear();
+
+ // prepared query support
+ bool exec();
+ enum BatchExecutionMode { ValuesAsRows, ValuesAsColumns };
+ bool execBatch(BatchExecutionMode mode = ValuesAsRows);
+ bool prepare(const QString& query);
+ void bindValue(const QString& placeholder, const QVariant& val,
+ QSql::ParamType type = QSql::In);
+ void bindValue(int pos, const QVariant& val, QSql::ParamType type = QSql::In);
+ void addBindValue(const QVariant& val, QSql::ParamType type = QSql::In);
+ QVariant boundValue(const QString& placeholder) const;
+ QVariant boundValue(int pos) const;
+ QMap<QString, QVariant> boundValues() const;
+ QString executedQuery() const;
+ QVariant lastInsertId() const;
+ void finish();
+ bool nextResult();
+
+private:
+ QSqlQueryPrivate* d;
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSQLQUERY_H
diff --git a/src/sql/kernel/qsqlrecord.cpp b/src/sql/kernel/qsqlrecord.cpp
new file mode 100644
index 0000000000..635e5e4e62
--- /dev/null
+++ b/src/sql/kernel/qsqlrecord.cpp
@@ -0,0 +1,605 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qsqlrecord.h"
+
+#include "qdebug.h"
+#include "qstringlist.h"
+#include "qatomic.h"
+#include "qsqlfield.h"
+#include "qstring.h"
+#include "qvector.h"
+
+QT_BEGIN_NAMESPACE
+
+class QSqlRecordPrivate
+{
+public:
+ QSqlRecordPrivate();
+ QSqlRecordPrivate(const QSqlRecordPrivate &other);
+
+ inline bool contains(int index) { return index >= 0 && index < fields.count(); }
+ QString createField(int index, const QString &prefix) const;
+
+ QVector<QSqlField> fields;
+ QAtomicInt ref;
+};
+
+QSqlRecordPrivate::QSqlRecordPrivate()
+{
+ ref = 1;
+}
+
+QSqlRecordPrivate::QSqlRecordPrivate(const QSqlRecordPrivate &other): fields(other.fields)
+{
+ ref = 1;
+}
+
+/*! \internal
+ Just for compat
+*/
+QString QSqlRecordPrivate::createField(int index, const QString &prefix) const
+{
+ QString f;
+ if (!prefix.isEmpty())
+ f = prefix + QLatin1Char('.');
+ f += fields.at(index).name();
+ return f;
+}
+
+/*!
+ \class QSqlRecord
+ \brief The QSqlRecord class encapsulates a database record.
+
+ \ingroup database
+ \ingroup shared
+ \inmodule QtSql
+
+ The QSqlRecord class encapsulates the functionality and
+ characteristics of a database record (usually a row in a table or
+ view within the database). QSqlRecord supports adding and
+ removing fields as well as setting and retrieving field values.
+
+ The values of a record's fields' can be set by name or position
+ with setValue(); if you want to set a field to null use
+ setNull(). To find the position of a field by name use indexOf(),
+ and to find the name of a field at a particular position use
+ fieldName(). Use field() to retrieve a QSqlField object for a
+ given field. Use contains() to see if the record contains a
+ particular field name.
+
+ When queries are generated to be executed on the database only
+ those fields for which isGenerated() is true are included in the
+ generated SQL.
+
+ A record can have fields added with append() or insert(), replaced
+ with replace(), and removed with remove(). All the fields can be
+ removed with clear(). The number of fields is given by count();
+ all their values can be cleared (to null) using clearValues().
+
+ \sa QSqlField, QSqlQuery::record()
+*/
+
+
+/*!
+ Constructs an empty record.
+
+ \sa isEmpty(), append(), insert()
+*/
+
+QSqlRecord::QSqlRecord()
+{
+ d = new QSqlRecordPrivate();
+}
+
+/*!
+ Constructs a copy of \a other.
+
+ QSqlRecord is \l{implicitly shared}. This means you can make copies
+ of a record in \l{constant time}.
+*/
+
+QSqlRecord::QSqlRecord(const QSqlRecord& other)
+{
+ d = other.d;
+ d->ref.ref();
+}
+
+/*!
+ Sets the record equal to \a other.
+
+ QSqlRecord is \l{implicitly shared}. This means you can make copies
+ of a record in \l{constant time}.
+*/
+
+QSqlRecord& QSqlRecord::operator=(const QSqlRecord& other)
+{
+ qAtomicAssign(d, other.d);
+ return *this;
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QSqlRecord::~QSqlRecord()
+{
+ if (!d->ref.deref())
+ delete d;
+}
+
+/*!
+ \fn bool QSqlRecord::operator!=(const QSqlRecord &other) const
+
+ Returns true if this object is not identical to \a other;
+ otherwise returns false.
+
+ \sa operator==()
+*/
+
+/*!
+ Returns true if this object is identical to \a other (i.e., has
+ the same fields in the same order); otherwise returns false.
+
+ \sa operator!=()
+*/
+bool QSqlRecord::operator==(const QSqlRecord &other) const
+{
+ return d->fields == other.d->fields;
+}
+
+/*!
+ Returns the value of the field located at position \a index in
+ the record. If \a index is out of bounds, an invalid QVariant
+ is returned.
+
+ \sa fieldName() isNull()
+*/
+
+QVariant QSqlRecord::value(int index) const
+{
+ return d->fields.value(index).value();
+}
+
+/*!
+ \overload
+
+ Returns the value of the field called \a name in the record. If
+ field \a name does not exist an invalid variant is returned.
+
+ \sa indexOf()
+*/
+
+QVariant QSqlRecord::value(const QString& name) const
+{
+ return value(indexOf(name));
+}
+
+/*!
+ Returns the name of the field at position \a index. If the field
+ does not exist, an empty string is returned.
+
+ \sa indexOf()
+*/
+
+QString QSqlRecord::fieldName(int index) const
+{
+ return d->fields.value(index).name();
+}
+
+/*!
+ Returns the position of the field called \a name within the
+ record, or -1 if it cannot be found. Field names are not
+ case-sensitive. If more than one field matches, the first one is
+ returned.
+
+ \sa fieldName()
+*/
+
+int QSqlRecord::indexOf(const QString& name) const
+{
+ QString nm = name.toUpper();
+ for (int i = 0; i < count(); ++i) {
+ if (d->fields.at(i).name().toUpper() == nm) // TODO: case-insensitive comparison
+ return i;
+ }
+ return -1;
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ \obsolete
+ Use field() instead
+*/
+const QSqlField* QSqlRecord::fieldPtr(int index) const
+{
+ if (!d->contains(index))
+ return 0;
+
+ return &d->fields.at(index);
+}
+
+/*!
+ \obsolete
+ Use field() instead
+*/
+
+const QSqlField* QSqlRecord::fieldPtr(const QString& name) const
+{
+ int i = indexOf(name);
+ if (!d->contains(i))
+ return 0;
+
+ return &d->fields.at(i);
+}
+#endif //QT3_SUPPORT
+
+/*!
+ Returns the field at position \a index. If the position is out of
+ range, an empty field is returned.
+ */
+QSqlField QSqlRecord::field(int index) const
+{
+ return d->fields.value(index);
+}
+
+/*! \overload
+ Returns the field called \a name.
+ */
+QSqlField QSqlRecord::field(const QString &name) const
+{
+ return field(indexOf(name));
+}
+
+
+/*!
+ Append a copy of field \a field to the end of the record.
+
+ \sa insert() replace() remove()
+*/
+
+void QSqlRecord::append(const QSqlField& field)
+{
+ detach();
+ d->fields.append(field);
+}
+
+/*!
+ Inserts the field \a field at position \a pos in the record.
+
+ \sa append() replace() remove()
+ */
+void QSqlRecord::insert(int pos, const QSqlField& field)
+{
+ detach();
+ d->fields.insert(pos, field);
+}
+
+/*!
+ Replaces the field at position \a pos with the given \a field. If
+ \a pos is out of range, nothing happens.
+
+ \sa append() insert() remove()
+*/
+
+void QSqlRecord::replace(int pos, const QSqlField& field)
+{
+ if (!d->contains(pos))
+ return;
+
+ detach();
+ d->fields[pos] = field;
+}
+
+/*!
+ Removes the field at position \a pos. If \a pos is out of range,
+ nothing happens.
+
+ \sa append() insert() replace()
+*/
+
+void QSqlRecord::remove(int pos)
+{
+ if (!d->contains(pos))
+ return;
+
+ detach();
+ d->fields.remove(pos);
+}
+
+/*!
+ Removes all the record's fields.
+
+ \sa clearValues() isEmpty()
+*/
+
+void QSqlRecord::clear()
+{
+ detach();
+ d->fields.clear();
+}
+
+/*!
+ Returns true if there are no fields in the record; otherwise
+ returns false.
+
+ \sa append() insert() clear()
+*/
+
+bool QSqlRecord::isEmpty() const
+{
+ return d->fields.isEmpty();
+}
+
+
+/*!
+ Returns true if there is a field in the record called \a name;
+ otherwise returns false.
+*/
+
+bool QSqlRecord::contains(const QString& name) const
+{
+ return indexOf(name) >= 0;
+}
+
+/*!
+ Clears the value of all fields in the record and sets each field
+ to null.
+
+ \sa setValue()
+*/
+
+void QSqlRecord::clearValues()
+{
+ detach();
+ int count = d->fields.count();
+ for (int i = 0; i < count; ++i)
+ d->fields[i].clear();
+}
+
+/*!
+ Sets the generated flag for the field called \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 QSqlQueryModel for example.
+
+ \sa isGenerated()
+*/
+
+void QSqlRecord::setGenerated(const QString& name, bool generated)
+{
+ setGenerated(indexOf(name), generated);
+}
+
+/*!
+ \overload
+
+ Sets the generated flag for the field \a index to \a generated.
+
+ \sa isGenerated()
+*/
+
+void QSqlRecord::setGenerated(int index, bool generated)
+{
+ if (!d->contains(index))
+ return;
+ detach();
+ d->fields[index].setGenerated(generated);
+}
+
+/*!
+ \overload
+
+ Returns true if the field \a index is null or if there is no field at
+ position \a index; otherwise returns false.
+*/
+bool QSqlRecord::isNull(int index) const
+{
+ return d->fields.value(index).isNull();
+}
+
+/*!
+ Returns true if the field called \a name is null or if there is no
+ field called \a name; otherwise returns false.
+
+ \sa setNull()
+*/
+bool QSqlRecord::isNull(const QString& name) const
+{
+ return isNull(indexOf(name));
+}
+
+/*!
+ Sets the value of field \a index to null. If the field does not exist,
+ nothing happens.
+
+ \sa setValue()
+*/
+void QSqlRecord::setNull(int index)
+{
+ if (!d->contains(index))
+ return;
+ detach();
+ d->fields[index].clear();
+}
+
+/*!
+ \overload
+
+ Sets the value of the field called \a name to null. If the field
+ does not exist, nothing happens.
+*/
+void QSqlRecord::setNull(const QString& name)
+{
+ setNull(indexOf(name));
+}
+
+
+/*!
+ Returns true if the record has a field called \a name and this
+ field is to be generated (the default); otherwise returns false.
+
+ \sa setGenerated()
+*/
+bool QSqlRecord::isGenerated(const QString& name) const
+{
+ return isGenerated(indexOf(name));
+}
+
+/*! \overload
+
+ Returns true if the record has a field at position \a index and this
+ field is to be generated (the default); otherwise returns false.
+
+ \sa setGenerated()
+*/
+bool QSqlRecord::isGenerated(int index) const
+{
+ return d->fields.value(index).isGenerated();
+}
+
+#ifdef QT3_SUPPORT
+/*!
+ Returns a list of all the record's field names as a string
+ separated by \a sep.
+
+ In the unlikely event that you used this function in Qt 3, you
+ can simulate it using the rest of the QSqlRecord public API.
+*/
+
+QString QSqlRecord::toString(const QString& prefix, const QString& sep) const
+{
+ QString pflist;
+ bool comma = false;
+ for (int i = 0; i < count(); ++i) {
+ if (!d->fields.value(i).isGenerated()) {
+ if (comma)
+ pflist += sep + QLatin1Char(' ');
+ pflist += d->createField(i, prefix);
+ comma = true;
+ }
+ }
+ return pflist;
+}
+
+/*!
+ Returns a list of all the record's field names, each having the
+ prefix \a prefix.
+
+ In the unlikely event that you used this function in Qt 3, you
+ can simulate it using the rest of the QSqlRecord public API.
+*/
+
+QStringList QSqlRecord::toStringList(const QString& prefix) const
+{
+ QStringList s;
+ for (int i = 0; i < count(); ++i) {
+ if (!d->fields.value(i).isGenerated())
+ s += d->createField(i, prefix);
+ }
+ return s;
+}
+#endif // QT3_SUPPORT
+
+/*!
+ Returns the number of fields in the record.
+
+ \sa isEmpty()
+*/
+
+int QSqlRecord::count() const
+{
+ return d->fields.count();
+}
+
+/*!
+ Sets the value of the field at position \a index to \a val. If the
+ field does not exist, nothing happens.
+
+ \sa setNull()
+*/
+
+void QSqlRecord::setValue(int index, const QVariant& val)
+{
+ if (!d->contains(index))
+ return;
+ detach();
+ d->fields[index].setValue(val);
+}
+
+
+/*!
+ \overload
+
+ Sets the value of the field called \a name to \a val. If the field
+ does not exist, nothing happens.
+*/
+
+void QSqlRecord::setValue(const QString& name, const QVariant& val)
+{
+ setValue(indexOf(name), val);
+}
+
+
+/*! \internal
+*/
+void QSqlRecord::detach()
+{
+ qAtomicDetach(d);
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug dbg, const QSqlRecord &r)
+{
+ dbg << "QSqlRecord(" << r.count() << ')';
+ for (int i = 0; i < r.count(); ++i)
+ dbg << '\n' << QString::fromLatin1("%1:").arg(i, 2) << r.field(i) << r.value(i).toString();
+ return dbg;
+}
+#endif
+
+/*!
+ \fn int QSqlRecord::position(const QString& name) const
+
+ Use indexOf() instead.
+*/
+
+QT_END_NAMESPACE
diff --git a/src/sql/kernel/qsqlrecord.h b/src/sql/kernel/qsqlrecord.h
new file mode 100644
index 0000000000..ed79dd8a02
--- /dev/null
+++ b/src/sql/kernel/qsqlrecord.h
@@ -0,0 +1,123 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQLRECORD_H
+#define QSQLRECORD_H
+
+#include <QtCore/qstring.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sql)
+
+class QSqlField;
+class QStringList;
+class QVariant;
+class QSqlRecordPrivate;
+
+class Q_SQL_EXPORT QSqlRecord
+{
+public:
+ QSqlRecord();
+ QSqlRecord(const QSqlRecord& other);
+ QSqlRecord& operator=(const QSqlRecord& other);
+ ~QSqlRecord();
+
+ bool operator==(const QSqlRecord &other) const;
+ inline bool operator!=(const QSqlRecord &other) const { return !operator==(other); }
+
+ QVariant value(int i) const;
+ QVariant value(const QString& name) const;
+ void setValue(int i, const QVariant& val);
+ void setValue(const QString& name, const QVariant& val);
+
+ void setNull(int i);
+ void setNull(const QString& name);
+ bool isNull(int i) const;
+ bool isNull(const QString& name) const;
+
+ int indexOf(const QString &name) const;
+ QString fieldName(int i) const;
+
+ QSqlField field(int i) const;
+ QSqlField field(const QString &name) const;
+
+ bool isGenerated(int i) const;
+ bool isGenerated(const QString& name) const;
+ void setGenerated(const QString& name, bool generated);
+ void setGenerated(int i, bool generated);
+
+#ifdef QT3_SUPPORT
+ QT3_SUPPORT const QSqlField* fieldPtr(int i) const;
+ QT3_SUPPORT const QSqlField* fieldPtr(const QString& name) const;
+ inline QT3_SUPPORT int position(const QString& name) const { return indexOf(name); }
+ QT3_SUPPORT QString toString(const QString& prefix = QString(),
+ const QString& sep = QLatin1String(",")) const;
+ QT3_SUPPORT QStringList toStringList(const QString& prefix = QString()) const;
+#endif
+
+ void append(const QSqlField& field);
+ void replace(int pos, const QSqlField& field);
+ void insert(int pos, const QSqlField& field);
+ void remove(int pos);
+
+ bool isEmpty() const;
+ bool contains(const QString& name) const;
+ void clear();
+ void clearValues();
+ int count() const;
+
+private:
+ void detach();
+ QSqlRecordPrivate* d;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_SQL_EXPORT QDebug operator<<(QDebug, const QSqlRecord &);
+#endif
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSQLRECORD_H
diff --git a/src/sql/kernel/qsqlresult.cpp b/src/sql/kernel/qsqlresult.cpp
new file mode 100644
index 0000000000..e8dcc044d2
--- /dev/null
+++ b/src/sql/kernel/qsqlresult.cpp
@@ -0,0 +1,1040 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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 "qvariant.h"
+#include "qhash.h"
+#include "qregexp.h"
+#include "qsqlerror.h"
+#include "qsqlfield.h"
+#include "qsqlrecord.h"
+#include "qsqlresult.h"
+#include "qvector.h"
+#include "qsqldriver.h"
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+
+struct QHolder {
+ QHolder(const QString& hldr = QString(), int index = -1): holderName(hldr), holderPos(index) {}
+ bool operator==(const QHolder& h) const { return h.holderPos == holderPos && h.holderName == holderName; }
+ bool operator!=(const QHolder& h) const { return h.holderPos != holderPos || h.holderName != holderName; }
+ QString holderName;
+ int holderPos;
+};
+
+class QSqlResultPrivate
+{
+public:
+ QSqlResultPrivate(QSqlResult* d)
+ : q(d), sqldriver(0), idx(QSql::BeforeFirstRow), active(false),
+ isSel(false), forwardOnly(false), precisionPolicy(QSql::LowPrecisionDouble), bindCount(0), binds(QSqlResult::PositionalBinding)
+ {}
+
+ void clearValues()
+ {
+ values.clear();
+ bindCount = 0;
+ }
+
+ void resetBindCount()
+ {
+ bindCount = 0;
+ }
+
+ void clearIndex()
+ {
+ indexes.clear();
+ holders.clear();
+ types.clear();
+ }
+
+ void clear()
+ {
+ clearValues();
+ clearIndex();;
+ }
+
+ QString positionalToNamedBinding();
+ QString namedToPositionalBinding();
+ QString holderAt(int index) const;
+
+public:
+ QSqlResult* q;
+ const QSqlDriver* sqldriver;
+ int idx;
+ QString sql;
+ bool active;
+ bool isSel;
+ QSqlError error;
+ bool forwardOnly;
+ QSql::NumericalPrecisionPolicy precisionPolicy;
+
+ int bindCount;
+ QSqlResult::BindingSyntax binds;
+
+ QString executedQuery;
+ QHash<int, QSql::ParamType> types;
+ QVector<QVariant> values;
+ typedef QHash<QString, int> IndexMap;
+ IndexMap indexes;
+
+ typedef QVector<QHolder> QHolderVector;
+ QHolderVector holders;
+};
+
+QString QSqlResultPrivate::holderAt(int index) const
+{
+ return indexes.key(index);
+}
+
+// return a unique id for bound names
+static QString qFieldSerial(int i)
+{
+ ushort arr[] = { ':', 'f', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
+ ushort *ptr = &arr[1];
+
+ while (i > 0) {
+ *(++ptr) = 'a' + i % 16;
+ i >>= 4;
+ }
+
+ return QString(reinterpret_cast<const QChar *>(arr), int(ptr - arr) + 1);
+}
+
+static bool qIsAlnum(QChar ch)
+{
+ uint u = uint(ch.unicode());
+ // matches [a-zA-Z0-9_]
+ return u - 'a' < 26 || u - 'A' < 26 || u - '0' < 10 || u == '_';
+}
+
+QString QSqlResultPrivate::positionalToNamedBinding()
+{
+ int n = sql.size();
+
+ QString result;
+ result.reserve(n * 5 / 4);
+ bool inQuote = false;
+ int count = 0;
+
+ for (int i = 0; i < n; ++i) {
+ QChar ch = sql.at(i);
+ if (ch == QLatin1Char('?') && !inQuote) {
+ result += qFieldSerial(count++);
+ } else {
+ if (ch == QLatin1Char('\''))
+ inQuote = !inQuote;
+ result += ch;
+ }
+ }
+ result.squeeze();
+ return result;
+}
+
+QString QSqlResultPrivate::namedToPositionalBinding()
+{
+ int n = sql.size();
+
+ QString result;
+ result.reserve(n);
+ bool inQuote = false;
+ int count = 0;
+ int i = 0;
+
+ while (i < n) {
+ QChar ch = sql.at(i);
+ if (ch == QLatin1Char(':') && !inQuote
+ && (i == 0 || sql.at(i - 1) != QLatin1Char(':'))
+ && (i < n - 1 && qIsAlnum(sql.at(i + 1)))) {
+ int pos = i + 2;
+ while (pos < n && qIsAlnum(sql.at(pos)))
+ ++pos;
+ indexes[sql.mid(i, pos - i)] = count++;
+ result += QLatin1Char('?');
+ i = pos;
+ } else {
+ if (ch == QLatin1Char('\''))
+ inQuote = !inQuote;
+ result += ch;
+ ++i;
+ }
+ }
+ result.squeeze();
+ return result;
+}
+
+/*!
+ \class QSqlResult
+ \brief The QSqlResult class provides an abstract interface for
+ accessing data from specific SQL databases.
+
+ \ingroup database
+ \inmodule QtSql
+
+ Normally, you would use QSqlQuery instead of QSqlResult, since
+ QSqlQuery provides a generic wrapper for database-specific
+ implementations of QSqlResult.
+
+ If you are implementing your own SQL driver (by subclassing
+ QSqlDriver), you will need to provide your own QSqlResult
+ subclass that implements all the pure virtual functions and other
+ virtual functions that you need.
+
+ \sa QSqlDriver
+*/
+
+/*!
+ \enum QSqlResult::BindingSyntax
+
+ This enum type specifies the different syntaxes for specifying
+ placeholders in prepared queries.
+
+ \value PositionalBinding Use the ODBC-style positional syntax, with "?" as placeholders.
+ \value NamedBinding Use the Oracle-style syntax with named placeholders (e.g., ":id")
+ \omitvalue BindByPosition
+ \omitvalue BindByName
+
+ \sa bindingSyntax()
+*/
+
+/*!
+ \enum QSqlResult::VirtualHookOperation
+ \internal
+*/
+
+/*!
+ Creates a QSqlResult using database driver \a db. The object is
+ initialized to an inactive state.
+
+ \sa isActive(), driver()
+*/
+
+QSqlResult::QSqlResult(const QSqlDriver *db)
+{
+ d = new QSqlResultPrivate(this);
+ d->sqldriver = db;
+ if(db) {
+ setNumericalPrecisionPolicy(db->numericalPrecisionPolicy());
+ }
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+QSqlResult::~QSqlResult()
+{
+ delete d;
+}
+
+/*!
+ Sets the current query for the result to \a query. You must call
+ reset() to execute the query on the database.
+
+ \sa reset(), lastQuery()
+*/
+
+void QSqlResult::setQuery(const QString& query)
+{
+ d->sql = query;
+}
+
+/*!
+ Returns the current SQL query text, or an empty string if there
+ isn't one.
+
+ \sa setQuery()
+*/
+
+QString QSqlResult::lastQuery() const
+{
+ return d->sql;
+}
+
+/*!
+ Returns the current (zero-based) row position of the result. May
+ return the special values QSql::BeforeFirstRow or
+ QSql::AfterLastRow.
+
+ \sa setAt(), isValid()
+*/
+int QSqlResult::at() const
+{
+ return d->idx;
+}
+
+
+/*!
+ Returns true if the result is positioned on a valid record (that
+ is, the result is not positioned before the first or after the
+ last record); otherwise returns false.
+
+ \sa at()
+*/
+
+bool QSqlResult::isValid() const
+{
+ return d->idx != QSql::BeforeFirstRow && d->idx != QSql::AfterLastRow;
+}
+
+/*!
+ \fn bool QSqlResult::isNull(int index)
+
+ Returns true if the field at position \a index in the current row
+ is null; otherwise returns false.
+*/
+
+/*!
+ Returns true if the result has records to be retrieved; otherwise
+ returns false.
+*/
+
+bool QSqlResult::isActive() const
+{
+ return d->active;
+}
+
+/*!
+ This function is provided for derived classes to set the
+ internal (zero-based) row position to \a index.
+
+ \sa at()
+*/
+
+void QSqlResult::setAt(int index)
+{
+ d->idx = index;
+}
+
+
+/*!
+ This function is provided for derived classes to indicate whether
+ or not the current statement is a SQL \c SELECT statement. The \a
+ select parameter should be true if the statement is a \c SELECT
+ statement; otherwise it should be false.
+
+ \sa isSelect()
+*/
+
+void QSqlResult::setSelect(bool select)
+{
+ d->isSel = select;
+}
+
+/*!
+ Returns true if the current result is from a \c SELECT statement;
+ otherwise returns false.
+
+ \sa setSelect()
+*/
+
+bool QSqlResult::isSelect() const
+{
+ return d->isSel;
+}
+
+/*!
+ Returns the driver associated with the result. This is the object
+ that was passed to the constructor.
+*/
+
+const QSqlDriver *QSqlResult::driver() const
+{
+ return d->sqldriver;
+}
+
+
+/*!
+ This function is provided for derived classes to set the internal
+ active state to \a active.
+
+ \sa isActive()
+*/
+
+void QSqlResult::setActive(bool active)
+{
+ if (active && d->executedQuery.isEmpty())
+ d->executedQuery = d->sql;
+
+ d->active = active;
+}
+
+/*!
+ This function is provided for derived classes to set the last
+ error to \a error.
+
+ \sa lastError()
+*/
+
+void QSqlResult::setLastError(const QSqlError &error)
+{
+ d->error = error;
+}
+
+
+/*!
+ Returns the last error associated with the result.
+*/
+
+QSqlError QSqlResult::lastError() const
+{
+ return d->error;
+}
+
+/*!
+ \fn int QSqlResult::size()
+
+ Returns the size of the \c SELECT result, or -1 if it cannot be
+ determined or if the query is not a \c SELECT statement.
+
+ \sa numRowsAffected()
+*/
+
+/*!
+ \fn int QSqlResult::numRowsAffected()
+
+ Returns the number of rows affected by the last query executed, or
+ -1 if it cannot be determined or if the query is a \c SELECT
+ statement.
+
+ \sa size()
+*/
+
+/*!
+ \fn QVariant QSqlResult::data(int index)
+
+ Returns the data for field \a index in the current row as
+ a QVariant. This function is only called if the result is in
+ an active state and is positioned on a valid record and \a index is
+ non-negative. Derived classes must reimplement this function and
+ return the value of field \a index, or QVariant() if it cannot be
+ determined.
+*/
+
+/*!
+ \fn bool QSqlResult::reset(const QString &query)
+
+ Sets the result to use the SQL statement \a query for subsequent
+ data retrieval.
+
+ Derived classes must reimplement this function and apply the \a
+ query to the database. This function is only called after the
+ result is set to an inactive state and is positioned before the
+ first record of the new result. Derived classes should return
+ true if the query was successful and ready to be used, or false
+ otherwise.
+
+ \sa setQuery()
+*/
+
+/*!
+ \fn bool QSqlResult::fetch(int index)
+
+ Positions the result to an arbitrary (zero-based) row \a index.
+
+ This function is only called if the result is in an active state.
+ Derived classes must reimplement this function and position the
+ result to the row \a index, and call setAt() with an appropriate
+ value. Return true to indicate success, or false to signify
+ failure.
+
+ \sa isActive(), fetchFirst(), fetchLast(), fetchNext(), fetchPrevious()
+*/
+
+/*!
+ \fn bool QSqlResult::fetchFirst()
+
+ Positions the result to the first record (row 0) in the result.
+
+ This function is only called if the result is in an active state.
+ Derived classes must reimplement this function and position the
+ result to the first record, and call setAt() with an appropriate
+ value. Return true to indicate success, or false to signify
+ failure.
+
+ \sa fetch(), fetchLast()
+*/
+
+/*!
+ \fn bool QSqlResult::fetchLast()
+
+ Positions the result to the last record (last row) in the result.
+
+ This function is only called if the result is in an active state.
+ Derived classes must reimplement this function and position the
+ result to the last record, and call setAt() with an appropriate
+ value. Return true to indicate success, or false to signify
+ failure.
+
+ \sa fetch(), fetchFirst()
+*/
+
+/*!
+ Positions the result to the next available record (row) in the
+ result.
+
+ This function is only called if the result is in an active
+ state. The default implementation calls fetch() with the next
+ index. Derived classes can reimplement this function and position
+ the result to the next record in some other way, and call setAt()
+ with an appropriate value. Return true to indicate success, or
+ false to signify failure.
+
+ \sa fetch(), fetchPrevious()
+*/
+
+bool QSqlResult::fetchNext()
+{
+ return fetch(at() + 1);
+}
+
+/*!
+ Positions the result to the previous record (row) in the result.
+
+ This function is only called if the result is in an active state.
+ The default implementation calls fetch() with the previous index.
+ Derived classes can reimplement this function and position the
+ result to the next record in some other way, and call setAt()
+ with an appropriate value. Return true to indicate success, or
+ false to signify failure.
+*/
+
+bool QSqlResult::fetchPrevious()
+{
+ return fetch(at() - 1);
+}
+
+/*!
+ Returns true if you can only scroll forward through the result
+ set; otherwise returns false.
+
+ \sa setForwardOnly()
+*/
+bool QSqlResult::isForwardOnly() const
+{
+ return d->forwardOnly;
+}
+
+/*!
+ Sets forward only mode to \a forward. If \a forward is true, only
+ fetchNext() is allowed for navigating the results. Forward only
+ mode needs much less memory since results do not have to be
+ cached. By default, this feature is disabled.
+
+ 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.
+
+ \note Calling setForwardOnly after execution of the query will result
+ in unexpected results at best, and crashes at worst.
+
+ \sa isForwardOnly(), fetchNext(), QSqlQuery::setForwardOnly()
+*/
+void QSqlResult::setForwardOnly(bool forward)
+{
+ d->forwardOnly = forward;
+}
+
+/*!
+ Prepares the given \a query, using the underlying database
+ functionality where possible. Returns true if the query is
+ prepared successfully; otherwise returns false.
+
+ \sa prepare()
+*/
+bool QSqlResult::savePrepare(const QString& query)
+{
+ if (!driver())
+ return false;
+ d->clear();
+ d->sql = query;
+ if (!driver()->hasFeature(QSqlDriver::PreparedQueries))
+ return prepare(query);
+
+ if (driver()->hasFeature(QSqlDriver::NamedPlaceholders)) {
+ // parse the query to memorize parameter location
+ d->namedToPositionalBinding();
+ d->executedQuery = d->positionalToNamedBinding();
+ } else {
+ d->executedQuery = d->namedToPositionalBinding();
+ }
+ return prepare(d->executedQuery);
+}
+
+/*!
+ Prepares the given \a query for execution; the query will normally
+ use placeholders so that it can be executed repeatedly. Returns
+ true if the query is prepared successfully; otherwise returns false.
+
+ \sa exec()
+*/
+bool QSqlResult::prepare(const QString& query)
+{
+ int n = query.size();
+
+ bool inQuote = false;
+ int i = 0;
+
+ while (i < n) {
+ QChar ch = query.at(i);
+ if (ch == QLatin1Char(':') && !inQuote
+ && (i == 0 || query.at(i - 1) != QLatin1Char(':'))
+ && (i < n - 1 && qIsAlnum(query.at(i + 1)))) {
+ int pos = i + 2;
+ while (pos < n && qIsAlnum(query.at(pos)))
+ ++pos;
+
+ d->holders.append(QHolder(query.mid(i, pos - i), i));
+ i = pos;
+ } else {
+ if (ch == QLatin1Char('\''))
+ inQuote = !inQuote;
+ ++i;
+ }
+ }
+ d->sql = query;
+ return true; // fake prepares should always succeed
+}
+
+/*!
+ Executes the query, returning true if successful; otherwise returns
+ false.
+
+ \sa prepare()
+*/
+bool QSqlResult::exec()
+{
+ bool ret;
+ // fake preparation - just replace the placeholders..
+ QString query = lastQuery();
+ if (d->binds == NamedBinding) {
+ int i;
+ QVariant val;
+ QString holder;
+ for (i = d->holders.count() - 1; i >= 0; --i) {
+ holder = d->holders.at(i).holderName;
+ val = d->values.value(d->indexes.value(holder));
+ QSqlField f(QLatin1String(""), val.type());
+ f.setValue(val);
+ query = query.replace(d->holders.at(i).holderPos,
+ holder.length(), driver()->formatValue(f));
+ }
+ } else {
+ QString val;
+ int i = 0;
+ int idx = 0;
+ for (idx = 0; idx < d->values.count(); ++idx) {
+ i = query.indexOf(QLatin1Char('?'), i);
+ if (i == -1)
+ continue;
+ QVariant var = d->values.value(idx);
+ QSqlField f(QLatin1String(""), var.type());
+ if (var.isNull())
+ f.clear();
+ else
+ f.setValue(var);
+ val = driver()->formatValue(f);
+ query = query.replace(i, 1, driver()->formatValue(f));
+ i += val.length();
+ }
+ }
+
+ // have to retain the original query with placeholders
+ QString orig = lastQuery();
+ ret = reset(query);
+ d->executedQuery = query;
+ setQuery(orig);
+ d->resetBindCount();
+ return ret;
+}
+
+/*!
+ Binds the value \a val of parameter type \a paramType to position \a index
+ in the current record (row).
+
+ \sa addBindValue()
+*/
+void QSqlResult::bindValue(int index, const QVariant& val, QSql::ParamType paramType)
+{
+ d->binds = PositionalBinding;
+ d->indexes[qFieldSerial(index)] = index;
+ if (d->values.count() <= index)
+ d->values.resize(index + 1);
+ d->values[index] = val;
+ if (paramType != QSql::In || !d->types.isEmpty())
+ d->types[index] = paramType;
+}
+
+/*!
+ \overload
+
+ Binds the value \a val of parameter type \a paramType to the \a
+ placeholder name in the current record (row).
+
+ Values cannot be bound to multiple locations in the query, eg:
+ \code
+ INSERT INTO testtable (id, name, samename) VALUES (:id, :name, :name)
+ \endcode
+ Binding to name will bind to the first :name, but not the second.
+
+ \note Binding an undefined placeholder will result in undefined behavior.
+
+ \sa QSqlQuery::bindValue()
+*/
+void QSqlResult::bindValue(const QString& placeholder, const QVariant& val,
+ QSql::ParamType paramType)
+{
+ d->binds = NamedBinding;
+ // if the index has already been set when doing emulated named
+ // bindings - don't reset it
+ int idx = d->indexes.value(placeholder, -1);
+ if (idx >= 0) {
+ if (d->values.count() <= idx)
+ d->values.resize(idx + 1);
+ d->values[idx] = val;
+ } else {
+ d->values.append(val);
+ idx = d->values.count() - 1;
+ d->indexes[placeholder] = idx;
+ }
+
+ if (paramType != QSql::In || !d->types.isEmpty())
+ d->types[idx] = paramType;
+}
+
+/*!
+ Binds the value \a val of parameter type \a paramType to the next
+ available position in the current record (row).
+
+ \sa bindValue()
+*/
+void QSqlResult::addBindValue(const QVariant& val, QSql::ParamType paramType)
+{
+ d->binds = PositionalBinding;
+ bindValue(d->bindCount, val, paramType);
+ ++d->bindCount;
+}
+
+/*!
+ Returns the value bound at position \a index in the current record
+ (row).
+
+ \sa bindValue(), boundValues()
+*/
+QVariant QSqlResult::boundValue(int index) const
+{
+ return d->values.value(index);
+}
+
+/*!
+ \overload
+
+ Returns the value bound by the given \a placeholder name in the
+ current record (row).
+
+ \sa bindValueType()
+*/
+QVariant QSqlResult::boundValue(const QString& placeholder) const
+{
+ int idx = d->indexes.value(placeholder, -1);
+ return d->values.value(idx);
+}
+
+/*!
+ Returns the parameter type for the value bound at position \a index.
+
+ \sa boundValue()
+*/
+QSql::ParamType QSqlResult::bindValueType(int index) const
+{
+ return d->types.value(index, QSql::In);
+}
+
+/*!
+ \overload
+
+ Returns the parameter type for the value bound with the given \a
+ placeholder name.
+*/
+QSql::ParamType QSqlResult::bindValueType(const QString& placeholder) const
+{
+ return d->types.value(d->indexes.value(placeholder, -1), QSql::In);
+}
+
+/*!
+ Returns the number of bound values in the result.
+
+ \sa boundValues()
+*/
+int QSqlResult::boundValueCount() const
+{
+ return d->values.count();
+}
+
+/*!
+ Returns a vector of the result's bound values for the current
+ record (row).
+
+ \sa boundValueCount()
+*/
+QVector<QVariant>& QSqlResult::boundValues() const
+{
+ return d->values;
+}
+
+/*!
+ Returns the binding syntax used by prepared queries.
+*/
+QSqlResult::BindingSyntax QSqlResult::bindingSyntax() const
+{
+ return d->binds;
+}
+
+/*!
+ Clears the entire result set and releases any associated
+ resources.
+*/
+void QSqlResult::clear()
+{
+ d->clear();
+}
+
+/*!
+ Returns the query that was actually executed. This may differ from
+ the query that was passed, for example if bound values were used
+ with a prepared query and the underlying database doesn't support
+ prepared queries.
+
+ \sa exec(), setQuery()
+*/
+QString QSqlResult::executedQuery() const
+{
+ return d->executedQuery;
+}
+
+void QSqlResult::resetBindCount()
+{
+ d->resetBindCount();
+}
+
+/*!
+ Returns the name of the bound value at position \a index in the
+ current record (row).
+
+ \sa boundValue()
+*/
+QString QSqlResult::boundValueName(int index) const
+{
+ return d->holderAt(index);
+}
+
+/*!
+ Returns true if at least one of the query's bound values is a \c
+ QSql::Out or a QSql::InOut; otherwise returns false.
+
+ \sa bindValueType()
+*/
+bool QSqlResult::hasOutValues() const
+{
+ if (d->types.isEmpty())
+ return false;
+ QHash<int, QSql::ParamType>::ConstIterator it;
+ for (it = d->types.constBegin(); it != d->types.constEnd(); ++it) {
+ if (it.value() != QSql::In)
+ return true;
+ }
+ return false;
+}
+
+/*!
+ Returns the current record if the query is active; otherwise
+ returns an empty QSqlRecord.
+
+ The default implementation always returns an empty QSqlRecord.
+
+ \sa isActive()
+*/
+QSqlRecord QSqlResult::record() const
+{
+ return QSqlRecord();
+}
+
+/*!
+ 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.
+
+ Note that for Oracle databases the row's ROWID will be returned,
+ while for MySQL databases the row's auto-increment field will
+ be returned.
+
+ \sa QSqlDriver::hasFeature()
+*/
+QVariant QSqlResult::lastInsertId() const
+{
+ return QVariant();
+}
+
+/*! \internal
+*/
+void QSqlResult::virtual_hook(int, void *)
+{
+}
+
+/*! \internal
+ \since 4.2
+
+ Executes a prepared query in batch mode if the driver supports it,
+ otherwise emulates a batch execution using bindValue() and exec().
+ QSqlDriver::hasFeature() can be used to find out whether a driver
+ supports batch execution.
+
+ Batch execution can be faster for large amounts of data since it
+ reduces network roundtrips.
+
+ For batch executions, bound values have to be provided as lists
+ of variants (QVariantList).
+
+ Each list must contain values of the same type. All lists must
+ contain equal amount of values (rows).
+
+ NULL values are passed in as typed QVariants, for example
+ \c {QVariant(QVariant::Int)} for an integer NULL value.
+
+ Example:
+
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqlresult.cpp 0
+
+ Here, we insert two rows into a SQL table, with each row containing three values.
+
+ \sa exec(), QSqlDriver::hasFeature()
+*/
+bool QSqlResult::execBatch(bool arrayBind)
+{
+ if (driver()->hasFeature(QSqlDriver::BatchOperations)) {
+ virtual_hook(BatchOperation, &arrayBind);
+ d->resetBindCount();
+ return d->error.type() == QSqlError::NoError;
+ } else {
+ QVector<QVariant> values = d->values;
+ if (values.count() == 0)
+ return false;
+ for (int i = 0; i < values.at(0).toList().count(); ++i) {
+ for (int j = 0; j < values.count(); ++j)
+ bindValue(j, values.at(j).toList().at(i), QSql::In);
+ if (!exec())
+ return false;
+ }
+ return true;
+ }
+ return false;
+}
+
+/*! \internal
+ */
+void QSqlResult::detachFromResultSet()
+{
+ if (driver()->hasFeature(QSqlDriver::FinishQuery)
+ || driver()->hasFeature(QSqlDriver::SimpleLocking))
+ virtual_hook(DetachFromResultSet, 0);
+}
+
+/*! \internal
+ */
+void QSqlResult::setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy)
+{
+ d->precisionPolicy = policy;
+ virtual_hook(SetNumericalPrecision, &policy);
+}
+
+/*! \internal
+ */
+QSql::NumericalPrecisionPolicy QSqlResult::numericalPrecisionPolicy() const
+{
+ return d->precisionPolicy;
+}
+
+/*! \internal
+*/
+bool QSqlResult::nextResult()
+{
+ if (driver()->hasFeature(QSqlDriver::MultipleResultSets)) {
+ bool result = false;
+ virtual_hook(NextResult, &result);
+ return result;
+ }
+ return false;
+}
+
+/*!
+ Returns the low-level database handle for this result set
+ wrapped in a QVariant or an invalid QVariant if there is no handle.
+
+ \warning Use this with uttermost care and only if you know what you're doing.
+
+ \warning The handle returned here can become a stale pointer if the result
+ is modified (for example, if you clear it).
+
+ \warning The handle can be NULL if the result was not executed yet.
+
+ The handle returned here is database-dependent, you should query the type
+ name of the variant before accessing it.
+
+ This example retrieves the handle for a sqlite result:
+
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqlresult.cpp 1
+
+ This snippet returns the handle for PostgreSQL or MySQL:
+
+ \snippet doc/src/snippets/code/src_sql_kernel_qsqlresult.cpp 2
+
+ \sa QSqlDriver::handle()
+*/
+QVariant QSqlResult::handle() const
+{
+ return QVariant();
+}
+
+QT_END_NAMESPACE
diff --git a/src/sql/kernel/qsqlresult.h b/src/sql/kernel/qsqlresult.h
new file mode 100644
index 0000000000..d216eac062
--- /dev/null
+++ b/src/sql/kernel/qsqlresult.h
@@ -0,0 +1,153 @@
+/****************************************************************************
+**
+** Copyright (C) 2011 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$
+**
+****************************************************************************/
+
+#ifndef QSQLRESULT_H
+#define QSQLRESULT_H
+
+#include <QtCore/qvariant.h>
+#include <QtCore/qvector.h>
+#include <QtSql/qsql.h>
+
+QT_BEGIN_HEADER
+
+QT_BEGIN_NAMESPACE
+
+QT_MODULE(Sql)
+
+class QString;
+class QSqlRecord;
+template <typename T> class QVector;
+class QVariant;
+class QSqlDriver;
+class QSqlError;
+class QSqlResultPrivate;
+
+class Q_SQL_EXPORT QSqlResult
+{
+ friend class QSqlQuery;
+ friend class QSqlTableModelPrivate;
+ friend class QSqlResultPrivate;
+
+public:
+ virtual ~QSqlResult();
+ virtual QVariant handle() const;
+
+protected:
+ enum BindingSyntax {
+ PositionalBinding,
+ NamedBinding
+#ifdef QT3_SUPPORT
+ , BindByPosition = PositionalBinding,
+ BindByName = NamedBinding
+#endif
+ };
+
+ explicit QSqlResult(const QSqlDriver * db);
+ int at() const;
+ QString lastQuery() const;
+ QSqlError lastError() const;
+ bool isValid() const;
+ bool isActive() const;
+ bool isSelect() const;
+ bool isForwardOnly() const;
+ const QSqlDriver* driver() const;
+ virtual void setAt(int at);
+ virtual void setActive(bool a);
+ virtual void setLastError(const QSqlError& e);
+ virtual void setQuery(const QString& query);
+ virtual void setSelect(bool s);
+ virtual void setForwardOnly(bool forward);
+
+ // prepared query support
+ virtual bool exec();
+ virtual bool prepare(const QString& query);
+ virtual bool savePrepare(const QString& sqlquery);
+ virtual void bindValue(int pos, const QVariant& val, QSql::ParamType type);
+ virtual void bindValue(const QString& placeholder, const QVariant& val,
+ QSql::ParamType type);
+ void addBindValue(const QVariant& val, QSql::ParamType type);
+ QVariant boundValue(const QString& placeholder) const;
+ QVariant boundValue(int pos) const;
+ QSql::ParamType bindValueType(const QString& placeholder) const;
+ QSql::ParamType bindValueType(int pos) const;
+ int boundValueCount() const;
+ QVector<QVariant>& boundValues() const;
+ QString executedQuery() const;
+ QString boundValueName(int pos) const;
+ void clear();
+ bool hasOutValues() const;
+
+ BindingSyntax bindingSyntax() const;
+
+ virtual QVariant data(int i) = 0;
+ virtual bool isNull(int i) = 0;
+ virtual bool reset(const QString& sqlquery) = 0;
+ virtual bool fetch(int i) = 0;
+ virtual bool fetchNext();
+ virtual bool fetchPrevious();
+ virtual bool fetchFirst() = 0;
+ virtual bool fetchLast() = 0;
+ virtual int size() = 0;
+ virtual int numRowsAffected() = 0;
+ virtual QSqlRecord record() const;
+ virtual QVariant lastInsertId() const;
+
+ enum VirtualHookOperation { BatchOperation, DetachFromResultSet, SetNumericalPrecision, NextResult };
+ virtual void virtual_hook(int id, void *data);
+ bool execBatch(bool arrayBind = false);
+ void detachFromResultSet();
+ void setNumericalPrecisionPolicy(QSql::NumericalPrecisionPolicy policy);
+ QSql::NumericalPrecisionPolicy numericalPrecisionPolicy() const;
+ bool nextResult();
+
+private:
+ QSqlResultPrivate* d;
+ void resetBindCount(); // HACK
+
+private:
+ Q_DISABLE_COPY(QSqlResult)
+};
+
+QT_END_NAMESPACE
+
+QT_END_HEADER
+
+#endif // QSQLRESULT_H