📄 qsqldatabase.cpp
字号:
/******************************************************************************** Copyright (C) 1992-2007 Trolltech ASA. All rights reserved.**** This file is part of the QtSql module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://trolltech.com/products/qt/licenses/licensing/opensource/**** If you are unsure which license is appropriate for your use, please** review the following information:** http://trolltech.com/products/qt/licenses/licensing/licensingoverview** or contact the sales department at sales@trolltech.com.**** In addition, as a special exception, Trolltech gives you certain** additional rights. These rights are described in the Trolltech GPL** Exception version 1.0, which can be found at** http://www.trolltech.com/products/qt/gplexception/ and in the file** GPL_EXCEPTION.txt in this package.**** In addition, as a special exception, Trolltech, as the sole copyright** holder for Qt Designer, grants users of the Qt/Eclipse Integration** plug-in the right for the Qt/Eclipse Integration to link to** functionality provided by Qt Designer and its related libraries.**** Trolltech reserves all rights not expressly granted herein.**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#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>#ifndef QT_NO_LIBRARYQ_GLOBAL_STATIC_WITH_ARGS(QFactoryLoader, loader, (QSqlDriverFactoryInterface_iid, QCoreApplication::libraryPaths(), QLatin1String("/sqldrivers")))#endifQT_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(QSqlDriver *dr = 0): driver(dr), port(-1) { ref = 1; } QSqlDatabasePrivate(const QSqlDatabasePrivate &other); ~QSqlDatabasePrivate(); void init(const QString& type); void copy(const QSqlDatabasePrivate *other); void disable(); QAtomic ref; QSqlDriver* driver; QString dbname; QString uname; QString pword; QString hname; QString drvName; int port; QString connOptions; 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; dbname = other.dbname; uname = other.uname; pword = other.pword; hname = other.hname; drvName = other.drvName; port = other.port; connOptions = other.connOptions; driver = other.driver;}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(&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(); }}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);}/*! \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) { db.open(); if (!db.isOpen()) qWarning("QSqlDatabasePrivate::database: unable to open database: %s", db.lastError().text().toLocal8Bit().data()); } return db;}/*! \internal Copies the connection data from \a other.*/void QSqlDatabasePrivate::copy(const QSqlDatabasePrivate *other){ dbname = other->dbname; uname = other->uname; pword = other->pword; hname = other->hname; drvName = other->drvName; port = other->port; connOptions = other->connOptions;}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 \module sql 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 \module sql 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 \mainclass \module sql The QSqlDatabase class provides an abstract interface for accessing database backends. It relies on database-specific \l{QSqlDriver}s to actually access and manipulate data. The following code shows how to initialize a connection: \quotefromfile snippets/sqldatabase/sqldatabase.cpp \skipto QSqlDatabase_snippet \skipto QSqlDatabase db = \printuntil db.open() Once a QSqlDatabase object has been created you can set the connection parameters with setDatabaseName(), setUserName(), setPassword(), setHostName(), setPort(), and setConnectOptions(). Once the parameters have been set up you can call open() to open the connection. The connection defined above is a nameless connection. It is the default connection and can be accessed using database() later on: \skipto QSqlDatabase db = \printline QSqlDatabase db = To make programming more convenient, QSqlDatabase is a value class. Any changes done to a database connection through one QSqlDatabase object will affect other QSqlDatabase objects representing the same connection. Call cloneDatabase() if you want to create an independent database connection based on an existing one. If you need multiple database connections simultaneously, specify an arbitrary name to addDatabase() and database(). Call removeDatabase() to remove connections. QSqlDatabase will output 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 see what tables the database offers with tables(), find the primary index for a table with primaryIndex(), get meta-information about a table's fields (e.g., their names) with record(), and execute a query with exec(). If transactions are supported, you can use transaction() to start a transaction, and then commit() or rollback() to complete it. You can find out whether transactions are supported using QSqlDriver::hasFeature(). When using transactions you must start the transaction before you create your query. If an error occurred, it is given by lastError(). The names of the underlying SQL drivers are available from drivers(); you can check for a particular driver with isDriverAvailable(). If you have created your own custom driver, you can register it with registerSqlDriver(). \sa QSqlDriver, QSqlQuery, {QtSql Module}, {Threads and the SQL Module}*//*! \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 connectionName is not specified, the newly added database connection becomes the default database connection for the application, and subsequent calls to database() without a database name parameter will return a reference to it. If \a connectionName is given, use database(\a connectionName) to retrieve a pointer to the database connection. \warning If you add a database with the same name as an existing database, the new database will replace the old one. This will happen automatically if you call this function more than once without specifying \a connectionName. To make use of the connection, you will need to set it up, for example by calling some or all of setDatabaseName(), setUserName(), setPassword(), setHostName(), setPort(), and setConnectOptions(), and then you'll need to open() the connection. \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: \code // WRONG QSqlDatabase db = QSqlDatabase::database("sales"); QSqlQuery query("SELECT NAME, DOB FROM EMPLOYEES", db); QSqlDatabase::removeDatabase("sales"); // will output a warning // "db" is now a dangling invalid database connection, // "query" contains an invalid result set \endcode The correct way to do it: \code { QSqlDatabase db = QSqlDatabase::database("sales"); QSqlQuery query("SELECT NAME, DOB FROM EMPLOYEES", db); } // Both "db" and "query" are destroyed because they are out of scope QSqlDatabase::removeDatabase("sales"); // correct \endcode \sa database() {Threads and the SQL Module}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -