summaryrefslogtreecommitdiffstats
path: root/src/sql/kernel
diff options
context:
space:
mode:
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