src/sql/kernel/qsqldatabase.cpp
changeset 0 1918ee327afb
child 4 3b1da2848fc7
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sql/kernel/qsqldatabase.cpp	Mon Jan 11 14:00:40 2010 +0000
@@ -0,0 +1,1543 @@
+/****************************************************************************
+**
+** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
+** All rights reserved.
+** Contact: Nokia Corporation (qt-info@nokia.com)
+**
+** This file is part of the QtSql module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** No Commercial Usage
+** This file contains pre-release code and may not be distributed.
+** You may use this file in accordance with the terms and conditions
+** contained in the Technology Preview License Agreement accompanying
+** this package.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Nokia gives you certain additional
+** rights.  These rights are described in the Nokia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** If you have questions regarding the use of this file, please contact
+** Nokia at qt-info@nokia.com.
+**
+**
+**
+**
+**
+**
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "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
+#include "../drivers/tds/qsql_tds.h"
+#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
+
+#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+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);
+    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());
+        ++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)
+{
+    if (db.d->ref != 1) {
+        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
+
+#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+    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();
+            }
+        }
+    }
+
+#if !defined(QT_NO_LIBRARY) && !defined(QT_NO_SETTINGS)
+    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 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
+    \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