diff options
author | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2011-07-10 15:24:15 -0500 |
---|---|---|
committer | Timothy Pearson <kb9vqf@pearsoncomputing.net> | 2011-07-10 15:24:15 -0500 |
commit | 7d523fac5a54f8e695e56f4877fa852608465bc7 (patch) | |
tree | f74237f64a396d91997032df9bdf674492529c94 /main/dependencies/qt3/src/sql | |
parent | 37e3f157c7d76f13de807fa66e36df209e1005fb (diff) | |
download | tde-7d523fac5a54f8e695e56f4877fa852608465bc7.tar.gz tde-7d523fac5a54f8e695e56f4877fa852608465bc7.zip |
Add Qt3 development HEAD version
Diffstat (limited to 'main/dependencies/qt3/src/sql')
58 files changed, 22917 insertions, 0 deletions
diff --git a/main/dependencies/qt3/src/sql/README.module b/main/dependencies/qt3/src/sql/README.module new file mode 100644 index 000000000..511d90e83 --- /dev/null +++ b/main/dependencies/qt3/src/sql/README.module @@ -0,0 +1,37 @@ +Before building the Qt library, the Qt SQL module can be enabled for +specific databases using 'configure'. 'configure' is located at the +top of your QTDIR. + +Specific databases drivers can be enabled using one of the following +options: + + ./configure [-qt-sql-<driver>] [-plugin-sql-<driver>] + +or disabled using the following option: + + ./configure [-no-sql-<driver>] + +Where <driver> is the name of the driver, for example 'psql'. This +will configure the Qt library to compile the specified driver into +the Qt lib itself. + +For example, to build the PostgreSQL driver directly into the Qt +library, configure Qt like this: + + ./configure -qt-sql-psql + +In addition, you may need to specify an extra include path, as some +database drivers require headers for the database they are using, +for example: + + ./configure -qt-sql-psql -I/usr/local/include + +If instead you need to build the PostgreSQL driver as a dynamically +loaded plugin, configure Qt like this: + + ./configure -plugin-sql-psql + +To compile drivers as dynamically loaded plugins, see the +QTDIR/plugins/src/sqldrivers directory. Use 'configure -help' +for a complete list of configure options. See the Qt documentation +for a complete list of supported database drivers. diff --git a/main/dependencies/qt3/src/sql/drivers/cache/qsqlcachedresult.cpp b/main/dependencies/qt3/src/sql/drivers/cache/qsqlcachedresult.cpp new file mode 100644 index 000000000..4891b97c7 --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/cache/qsqlcachedresult.cpp @@ -0,0 +1,259 @@ +/**************************************************************************** +** +** Implementation of cached Qt SQL result classes +** +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlcachedresult.h" +#include <qdatetime.h> + +#ifndef QT_NO_SQL +static const uint initial_cache_size = 128; + +class QtSqlCachedResultPrivate +{ +public: + QtSqlCachedResultPrivate(); + bool seek(int i); + void init(int count, bool fo); + void cleanup(); + QtSqlCachedResult::RowCache* next(); + void revertLast(); + + QtSqlCachedResult::RowsetCache *cache; + QtSqlCachedResult::RowCache *current; + int rowCacheEnd; + int colCount; + bool forwardOnly; +}; + +QtSqlCachedResultPrivate::QtSqlCachedResultPrivate(): + cache(0), current(0), rowCacheEnd(0), colCount(0), forwardOnly(FALSE) +{ +} + +void QtSqlCachedResultPrivate::cleanup() +{ + if (cache) { + for (int i = 0; i < rowCacheEnd; ++i) + delete (*cache)[i]; + delete cache; + cache = 0; + } + if (forwardOnly) + delete current; + current = 0; + forwardOnly = FALSE; + colCount = 0; + rowCacheEnd = 0; +} + +void QtSqlCachedResultPrivate::init(int count, bool fo) +{ + cleanup(); + forwardOnly = fo; + colCount = count; + if (fo) + current = new QtSqlCachedResult::RowCache(count); + else + cache = new QtSqlCachedResult::RowsetCache(initial_cache_size); +} + +QtSqlCachedResult::RowCache *QtSqlCachedResultPrivate::next() +{ + if (forwardOnly) + return current; + + Q_ASSERT(cache); + current = new QtSqlCachedResult::RowCache(colCount); + if (rowCacheEnd == (int)cache->size()) + cache->resize(cache->size() * 2); + cache->insert(rowCacheEnd++, current); + return current; +} + +bool QtSqlCachedResultPrivate::seek(int i) +{ + if (forwardOnly || i < 0) + return FALSE; + if (i >= rowCacheEnd) + return FALSE; + current = (*cache)[i]; + return TRUE; +} + +void QtSqlCachedResultPrivate::revertLast() +{ + if (forwardOnly) + return; + --rowCacheEnd; + delete current; + current = 0; +} + +////////////// + +QtSqlCachedResult::QtSqlCachedResult(const QSqlDriver * db ): QSqlResult ( db ) +{ + d = new QtSqlCachedResultPrivate(); +} + +QtSqlCachedResult::~QtSqlCachedResult() +{ + delete d; +} + +void QtSqlCachedResult::init(int colCount) +{ + d->init(colCount, isForwardOnly()); +} + +bool QtSqlCachedResult::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::AfterLast) + return FALSE; + while(at() < i - 1) { + if (!gotoNext(0)) + return FALSE; + setAt(at() + 1); + } + if (!gotoNext(d->current)) + return FALSE; + setAt(at() + 1); + return TRUE; + } + if (d->seek(i)) { + setAt(i); + return TRUE; + } + setAt(d->rowCacheEnd - 1); + while (at() < i) { + if (!cacheNext()) + return FALSE; + } + return TRUE; +} + +bool QtSqlCachedResult::fetchNext() +{ + if (d->seek(at() + 1)) { + setAt(at() + 1); + return TRUE; + } + return cacheNext(); +} + +bool QtSqlCachedResult::fetchPrev() +{ + return fetch(at() - 1); +} + +bool QtSqlCachedResult::fetchFirst() +{ + if (d->forwardOnly && at() != QSql::BeforeFirst) { + return FALSE; + } + if (d->seek(0)) { + setAt(0); + return TRUE; + } + return cacheNext(); +} + +bool QtSqlCachedResult::fetchLast() +{ + if (at() == QSql::AfterLast) { + if (d->forwardOnly) + return FALSE; + else + return fetch(d->rowCacheEnd - 1); + } + + int i = at(); + while (fetchNext()) + i++; /* brute force */ + if (d->forwardOnly && at() == QSql::AfterLast) { + setAt(i); + return TRUE; + } else { + return fetch(d->rowCacheEnd - 1); + } +} + +QVariant QtSqlCachedResult::data(int i) +{ + if (!d->current || i >= (int)d->current->size() || i < 0) + return QVariant(); + + return (*d->current)[i]; +} + +bool QtSqlCachedResult::isNull(int i) +{ + if (!d->current || i >= (int)d->current->size() || i < 0) + return TRUE; + + return (*d->current)[i].isNull(); +} + +void QtSqlCachedResult::cleanup() +{ + setAt(QSql::BeforeFirst); + setActive(FALSE); + d->cleanup(); +} + +bool QtSqlCachedResult::cacheNext() +{ + if (!gotoNext(d->next())) { + d->revertLast(); + return FALSE; + } + setAt(at() + 1); + return TRUE; +} + +int QtSqlCachedResult::colCount() const +{ + return d->colCount; +} +#endif // QT_NO_SQL diff --git a/main/dependencies/qt3/src/sql/drivers/cache/qsqlcachedresult.h b/main/dependencies/qt3/src/sql/drivers/cache/qsqlcachedresult.h new file mode 100644 index 000000000..e401eef69 --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/cache/qsqlcachedresult.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Definition of shared Qt SQL module classes +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLCACHEDRESULT_H +#define QSQLCACHEDRESULT_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 <qglobal.h> +#include <qvariant.h> +#include <qptrvector.h> +#include <qvaluevector.h> +#include <qsqlresult.h> + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL + +class QtSqlCachedResultPrivate; + +class QM_EXPORT_SQL QtSqlCachedResult: public QSqlResult +{ +public: + virtual ~QtSqlCachedResult(); + + typedef QValueVector<QVariant> RowCache; + typedef QPtrVector<RowCache> RowsetCache; + +protected: + QtSqlCachedResult(const QSqlDriver * db); + + void init(int colCount); + void cleanup(); + bool cacheNext(); + + virtual bool gotoNext(RowCache* row) = 0; + + QVariant data(int i); + bool isNull(int i); + bool fetch(int i); + bool fetchNext(); + bool fetchPrev(); + bool fetchFirst(); + bool fetchLast(); + + int colCount() const; + +private: + QtSqlCachedResultPrivate *d; +}; + + +#endif + +#endif diff --git a/main/dependencies/qt3/src/sql/drivers/ibase/qsql_ibase.cpp b/main/dependencies/qt3/src/sql/drivers/ibase/qsql_ibase.cpp new file mode 100644 index 000000000..6954ef87e --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/ibase/qsql_ibase.cpp @@ -0,0 +1,1078 @@ +/**************************************************************************** +** +** Implementation of Interbase driver classes. +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** EDITIONS: FREE, ENTERPRISE +** +** 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 "qsql_ibase.h" + +#include <qdatetime.h> +#include <private/qsqlextension_p.h> + +#include <ibase.h> +#include <stdlib.h> +#include <limits.h> +#include <math.h> + +#define QIBASE_DRIVER_NAME "QIBASE" + +class QIBasePreparedExtension : public QSqlExtension +{ +public: + QIBasePreparedExtension(QIBaseResult *r) + : result(r) {} + + bool prepare(const QString &query) + { + return result->prepare(query); + } + + bool exec() + { + return result->exec(); + } + + QIBaseResult *result; +}; + +static bool getIBaseError(QString& msg, ISC_STATUS* status, long &sqlcode) +{ + if (status[0] != 1 || status[1] <= 0) + return FALSE; + + sqlcode = isc_sqlcode(status); + char buf[512]; + isc_sql_interprete(sqlcode, buf, 512); + msg = QString::fromUtf8(buf); + return TRUE; +} + +static void createDA(XSQLDA *&sqlda) +{ + sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(1)); + sqlda->sqln = 1; + sqlda->sqld = 0; + sqlda->version = SQLDA_VERSION1; + sqlda->sqlvar[0].sqlind = 0; + sqlda->sqlvar[0].sqldata = 0; +} + +static void enlargeDA(XSQLDA *&sqlda, int n) +{ + free(sqlda); + sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(n)); + sqlda->sqln = n; + sqlda->version = SQLDA_VERSION1; +} + +static void initDA(XSQLDA *sqlda) +{ + for (int i = 0; i < sqlda->sqld; ++i) { + switch (sqlda->sqlvar[i].sqltype & ~1) { + case SQL_INT64: + case SQL_LONG: + case SQL_SHORT: + case SQL_FLOAT: + case SQL_DOUBLE: + case SQL_TIMESTAMP: + case SQL_TYPE_TIME: + case SQL_TYPE_DATE: + case SQL_TEXT: + case SQL_BLOB: + sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen); + break; + case SQL_VARYING: + sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen + sizeof(short)); + break; + default: + // not supported - do not bind. + sqlda->sqlvar[i].sqldata = 0; + break; + } + if (sqlda->sqlvar[i].sqltype & 1) { + sqlda->sqlvar[i].sqlind = (short*)malloc(sizeof(short)); + *(sqlda->sqlvar[i].sqlind) = 0; + } else { + sqlda->sqlvar[i].sqlind = 0; + } + } +} + +static void delDA(XSQLDA *&sqlda) +{ + if (!sqlda) + return; + for (int i = 0; i < sqlda->sqld; ++i) { + free(sqlda->sqlvar[i].sqlind); + free(sqlda->sqlvar[i].sqldata); + } + free(sqlda); + sqlda = 0; +} + +static QVariant::Type qIBaseTypeName(int iType) +{ + switch (iType) { + case blr_varying: + case blr_varying2: + case blr_text: + case blr_cstring: + case blr_cstring2: + return QVariant::String; + case blr_sql_time: + return QVariant::Time; + case blr_sql_date: + return QVariant::Date; + case blr_timestamp: + return QVariant::DateTime; + case blr_blob: + return QVariant::ByteArray; + case blr_quad: + case blr_short: + case blr_long: + return QVariant::Int; + case blr_int64: + return QVariant::LongLong; + case blr_float: + case blr_d_float: + case blr_double: + return QVariant::Double; + } + return QVariant::Invalid; +} + +static QVariant::Type qIBaseTypeName2(int iType) +{ + switch(iType & ~1) { + case SQL_VARYING: + case SQL_TEXT: + return QVariant::String; + case SQL_LONG: + case SQL_SHORT: + return QVariant::Int; + case SQL_INT64: + return QVariant::LongLong; + case SQL_FLOAT: + case SQL_DOUBLE: + return QVariant::Double; + case SQL_TIMESTAMP: + return QVariant::DateTime; + case SQL_TYPE_DATE: + return QVariant::Date; + case SQL_TYPE_TIME: + return QVariant::Time; + default: + return QVariant::Invalid; + } +} + +static ISC_TIME toTime(const QTime &t) +{ + static const QTime midnight(0, 0, 0, 0); + return (ISC_TIME)midnight.msecsTo(t) * 10; +} + +static ISC_DATE toDate(const QDate &d) +{ + static const QDate basedate(1858, 11, 17); + return (ISC_DATE)basedate.daysTo(d); +} + +static ISC_TIMESTAMP toTimeStamp(const QDateTime &dt) +{ + ISC_TIMESTAMP ts; + ts.timestamp_time = toTime(dt.time()); + ts.timestamp_date = toDate(dt.date()); + return ts; +} + +static QTime toQTime(ISC_TIME time) +{ + // have to demangle the structure ourselves because isc_decode_time + // strips the msecs + static const QTime t; + return t.addMSecs(time / 10); +} + +static QDate toQDate(ISC_DATE d) +{ + static const QDate bd(1858, 11, 17); + return bd.addDays(d); +} + +static QDateTime toQDateTime(ISC_TIMESTAMP *ts) +{ + return QDateTime(toQDate(ts->timestamp_date), toQTime(ts->timestamp_time)); +} + +class QIBaseDriverPrivate +{ +public: + QIBaseDriverPrivate(QIBaseDriver *d): q(d) + { + ibase = 0; + trans = 0; + } + + bool isError(const QString &msg = QString::null, QSqlError::Type typ = QSqlError::Unknown) + { + QString imsg; + long sqlcode; + if (!getIBaseError(imsg, status, sqlcode)) + return FALSE; + + q->setLastError(QSqlError(msg, imsg, typ, (int)sqlcode)); + return TRUE; + } + +public: + QIBaseDriver* q; + isc_db_handle ibase; + isc_tr_handle trans; + ISC_STATUS status[20]; +}; + +class QIBaseResultPrivate +{ +public: + QIBaseResultPrivate(QIBaseResult *d, const QIBaseDriver *ddb); + ~QIBaseResultPrivate() { cleanup(); } + + void cleanup(); + bool isError(const QString &msg = QString::null, QSqlError::Type typ = QSqlError::Unknown) + { + QString imsg; + long sqlcode; + if (!getIBaseError(imsg, status, sqlcode)) + return FALSE; + + q->setLastError(QSqlError(msg, imsg, typ, (int)sqlcode)); + return TRUE; + } + + bool transaction(); + bool commit(); + + bool isSelect(); + QVariant fetchBlob(ISC_QUAD *bId); + void writeBlob(int i, const QByteArray &ba); + +public: + QIBaseResult *q; + const QIBaseDriver *db; + ISC_STATUS status[20]; + isc_tr_handle trans; + //indicator whether we have a local transaction or a transaction on driver level + bool localTransaction; + isc_stmt_handle stmt; + isc_db_handle ibase; + XSQLDA *sqlda; // output sqlda + XSQLDA *inda; // input parameters + int queryType; +}; + +QIBaseResultPrivate::QIBaseResultPrivate(QIBaseResult *d, const QIBaseDriver *ddb): + q(d), db(ddb), trans(0), stmt(0), ibase(ddb->d->ibase), sqlda(0), inda(0), queryType(-1) +{ + localTransaction = (ddb->d->ibase == 0); +} + +void QIBaseResultPrivate::cleanup() +{ + if (stmt) { + isc_dsql_free_statement(status, &stmt, DSQL_drop); + stmt = 0; + } + + commit(); + if (!localTransaction) + trans = 0; + + delDA(sqlda); + delDA(inda); + + queryType = -1; + q->cleanup(); +} + +void QIBaseResultPrivate::writeBlob(int i, const QByteArray &ba) +{ + isc_blob_handle handle = 0; + ISC_QUAD *bId = (ISC_QUAD*)inda->sqlvar[i].sqldata; + isc_create_blob2(status, &ibase, &trans, &handle, bId, 0, 0); + if (!isError("Unable to create BLOB", QSqlError::Statement)) { + uint i = 0; + while (i < ba.size()) { + isc_put_segment(status, &handle, QMIN(ba.size() - i, SHRT_MAX), ba.data()); + if (isError("Unable to write BLOB")) + break; + i += SHRT_MAX; + } + } + isc_close_blob(status, &handle); +} + +QVariant QIBaseResultPrivate::fetchBlob(ISC_QUAD *bId) +{ + isc_blob_handle handle = 0; + + isc_open_blob2(status, &ibase, &trans, &handle, bId, 0, 0); + if (isError("Unable to open BLOB", QSqlError::Statement)) + return QVariant(); + + unsigned short len = 0; + QByteArray ba(255); + ISC_STATUS stat = isc_get_segment(status, &handle, &len, ba.size(), ba.data()); + while (status[1] == isc_segment) { + uint osize = ba.size(); + // double the amount of data fetched on each iteration + ba.resize(QMIN(ba.size() * 2, SHRT_MAX)); + stat = isc_get_segment(status, &handle, &len, osize, ba.data() + osize); + } + bool isErr = isError("Unable to read BLOB", QSqlError::Statement); + isc_close_blob(status, &handle); + if (isErr) + return QVariant(); + + if (ba.size() > 255) + ba.resize(ba.size() / 2 + len); + else + ba.resize(len); + + return ba; +} + +bool QIBaseResultPrivate::isSelect() +{ + char acBuffer[9]; + char qType = isc_info_sql_stmt_type; + isc_dsql_sql_info(status, &stmt, 1, &qType, sizeof(acBuffer), acBuffer); + if (isError("Could not get query info", QSqlError::Statement)) + return FALSE; + int iLength = isc_vax_integer(&acBuffer[1], 2); + queryType = isc_vax_integer(&acBuffer[3], iLength); + return (queryType == isc_info_sql_stmt_select); +} + +bool QIBaseResultPrivate::transaction() +{ + if (trans) + return TRUE; + if (db->d->trans) { + localTransaction = FALSE; + trans = db->d->trans; + return TRUE; + } + localTransaction = TRUE; + + isc_start_transaction(status, &trans, 1, &ibase, 0, NULL); + if (isError("Could not start transaction", QSqlError::Statement)) + return FALSE; + + return TRUE; +} + +// does nothing if the transaction is on the +// driver level +bool QIBaseResultPrivate::commit() +{ + if (!trans) + return FALSE; + // don't commit driver's transaction, the driver will do it for us + if (!localTransaction) + return TRUE; + + isc_commit_transaction(status, &trans); + trans = 0; + return !isError("Unable to commit transaction", QSqlError::Statement); +} + +////////// + +QIBaseResult::QIBaseResult(const QIBaseDriver* db): + QtSqlCachedResult(db) +{ + d = new QIBaseResultPrivate(this, db); + setExtension(new QIBasePreparedExtension(this)); +} + +QIBaseResult::~QIBaseResult() +{ + delete d; +} + +bool QIBaseResult::prepare(const QString& query) +{ + //qDebug("prepare: %s", query.ascii()); + if (!driver() || !driver()->isOpen() || driver()->isOpenError()) + return FALSE; + d->cleanup(); + setActive(FALSE); + setAt(QSql::BeforeFirst); + + createDA(d->sqlda); + createDA(d->inda); + + if (!d->transaction()) + return FALSE; + + isc_dsql_allocate_statement(d->status, &d->ibase, &d->stmt); + if (d->isError("Could not allocate statement", QSqlError::Statement)) + return FALSE; + isc_dsql_prepare(d->status, &d->trans, &d->stmt, 0, query.utf8().data(), 3, d->sqlda); + if (d->isError("Could not prepare statement", QSqlError::Statement)) + return FALSE; + + isc_dsql_describe_bind(d->status, &d->stmt, 1, d->inda); + if (d->isError("Could not describe input statement", QSqlError::Statement)) + return FALSE; + if (d->inda->sqld > d->inda->sqln) { + enlargeDA(d->inda, d->inda->sqld); + + isc_dsql_describe_bind(d->status, &d->stmt, 1, d->inda); + if (d->isError("Could not describe input statement", QSqlError::Statement)) + return FALSE; + } + initDA(d->inda); + if (d->sqlda->sqld > d->sqlda->sqln) { + // need more field descriptors + enlargeDA(d->sqlda, d->sqlda->sqld); + + isc_dsql_describe(d->status, &d->stmt, 1, d->sqlda); + if (d->isError("Could not describe statement", QSqlError::Statement)) + return FALSE; + } + initDA(d->sqlda); + + setSelect(d->isSelect()); + if (!isSelect()) { + free(d->sqlda); + d->sqlda = 0; + } + + return TRUE; +} + +bool QIBaseResult::exec() +{ + if (!driver() || !driver()->isOpen() || driver()->isOpenError()) + return FALSE; + setActive(FALSE); + setAt(QSql::BeforeFirst); + + if (d->inda && extension()->index.count() > 0) { + QMap<int, QString>::ConstIterator it; + if ((int)extension()->index.count() > d->inda->sqld) { + qWarning("QIBaseResult::exec: Parameter mismatch, expected %d, got %d parameters", d->inda->sqld, extension()->index.count()); + return FALSE; + } + int para = 0; + for (it = extension()->index.constBegin(); it != extension()->index.constEnd(); ++it, ++para) { + if (para >= d->inda->sqld) + break; + if (!d->inda->sqlvar[para].sqldata) + continue; + const QVariant val(extension()->values[it.data()].value); + if (d->inda->sqlvar[para].sqltype & 1) { + if (val.isNull()) { + // set null indicator + *(d->inda->sqlvar[para].sqlind) = 1; + // and set the value to 0, otherwise it would count as empty string. + *((short*)d->inda->sqlvar[para].sqldata) = 0; + continue; + } + // a value of 0 means non-null. + *(d->inda->sqlvar[para].sqlind) = 0; + } + switch(d->inda->sqlvar[para].sqltype & ~1) { + case SQL_INT64: + if (d->inda->sqlvar[para].sqlscale < 0) + *((Q_LLONG*)d->inda->sqlvar[para].sqldata) = Q_LLONG(val.toDouble() * + pow(10.0, d->inda->sqlvar[para].sqlscale * -1)); + else + *((Q_LLONG*)d->inda->sqlvar[para].sqldata) = val.toLongLong(); + break; + case SQL_LONG: + *((long*)d->inda->sqlvar[para].sqldata) = (long)val.toLongLong(); + break; + case SQL_SHORT: + *((short*)d->inda->sqlvar[para].sqldata) = (short)val.toInt(); + break; + case SQL_FLOAT: + *((float*)d->inda->sqlvar[para].sqldata) = (float)val.toDouble(); + break; + case SQL_DOUBLE: + *((double*)d->inda->sqlvar[para].sqldata) = val.toDouble(); + break; + case SQL_TIMESTAMP: + *((ISC_TIMESTAMP*)d->inda->sqlvar[para].sqldata) = toTimeStamp(val.toDateTime()); + break; + case SQL_TYPE_TIME: + *((ISC_TIME*)d->inda->sqlvar[para].sqldata) = toTime(val.toTime()); + break; + case SQL_TYPE_DATE: + *((ISC_DATE*)d->inda->sqlvar[para].sqldata) = toDate(val.toDate()); + break; + case SQL_VARYING: { + QCString str(val.toString().utf8()); // keep a copy of the string alive in this scope + short buflen = d->inda->sqlvar[para].sqllen; + if (str.length() < (uint)buflen) + buflen = str.length(); + *(short*)d->inda->sqlvar[para].sqldata = buflen; // first two bytes is the length + memcpy(d->inda->sqlvar[para].sqldata + sizeof(short), str.data(), buflen); + break; } + case SQL_TEXT: { + QCString str(val.toString().utf8().leftJustify(d->inda->sqlvar[para].sqllen, ' ', TRUE)); + memcpy(d->inda->sqlvar[para].sqldata, str.data(), d->inda->sqlvar[para].sqllen); + break; } + case SQL_BLOB: + d->writeBlob(para, val.toByteArray()); + break; + default: + break; + } + } + } + + if (colCount()) { + isc_dsql_free_statement(d->status, &d->stmt, DSQL_close); + if (d->isError("Unable to close statement")) + return FALSE; + cleanup(); + } + if (d->sqlda) + init(d->sqlda->sqld); + isc_dsql_execute2(d->status, &d->trans, &d->stmt, 1, d->inda, 0); + if (d->isError("Unable to execute query")) + return FALSE; + + setActive(TRUE); + return TRUE; +} + +bool QIBaseResult::reset (const QString& query) +{ +// qDebug("reset: %s", query.ascii()); + if (!driver() || !driver()->isOpen() || driver()->isOpenError()) + return FALSE; + d->cleanup(); + setActive(FALSE); + setAt(QSql::BeforeFirst); + + createDA(d->sqlda); + + if (!d->transaction()) + return FALSE; + + isc_dsql_allocate_statement(d->status, &d->ibase, &d->stmt); + if (d->isError("Could not allocate statement", QSqlError::Statement)) + return FALSE; + isc_dsql_prepare(d->status, &d->trans, &d->stmt, 0, query.utf8().data(), 3, d->sqlda); + if (d->isError("Could not prepare statement", QSqlError::Statement)) + return FALSE; + + if (d->sqlda->sqld > d->sqlda->sqln) { + // need more field descriptors + int n = d->sqlda->sqld; + free(d->sqlda); + d->sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(n)); + d->sqlda->sqln = n; + d->sqlda->version = SQLDA_VERSION1; + + isc_dsql_describe(d->status, &d->stmt, 1, d->sqlda); + if (d->isError("Could not describe statement", QSqlError::Statement)) + return FALSE; + } + + initDA(d->sqlda); + + setSelect(d->isSelect()); + if (isSelect()) { + init(d->sqlda->sqld); + } else { + free(d->sqlda); + d->sqlda = 0; + } + + isc_dsql_execute(d->status, &d->trans, &d->stmt, 1, 0); + if (d->isError("Unable to execute query")) + return FALSE; + + // commit non-select queries (if they are local) + if (!isSelect() && !d->commit()) + return FALSE; + + setActive(TRUE); + return TRUE; +} + +bool QIBaseResult::gotoNext(QtSqlCachedResult::RowCache* row) +{ + ISC_STATUS stat = isc_dsql_fetch(d->status, &d->stmt, 1, d->sqlda); + + if (stat == 100) { + // no more rows + setAt(QSql::AfterLast); + return FALSE; + } + if (d->isError("Could not fetch next item", QSqlError::Statement)) + return FALSE; + if (!row) // not interested in actual values + return TRUE; + + Q_ASSERT(row); + Q_ASSERT((int)row->size() == d->sqlda->sqld); + for (int i = 0; i < d->sqlda->sqld; ++i) { + char *buf = d->sqlda->sqlvar[i].sqldata; + int size = d->sqlda->sqlvar[i].sqllen; + Q_ASSERT(buf); + + if ((d->sqlda->sqlvar[i].sqltype & 1) && *d->sqlda->sqlvar[i].sqlind) { + // null value + QVariant v; + v.cast(qIBaseTypeName2(d->sqlda->sqlvar[i].sqltype)); + (*row)[i] = v; + continue; + } + + switch(d->sqlda->sqlvar[i].sqltype & ~1) { + case SQL_VARYING: + // pascal strings - a short with a length information followed by the data + (*row)[i] = QString::fromUtf8(buf + sizeof(short), *(short*)buf); + break; + case SQL_INT64: + if (d->sqlda->sqlvar[i].sqlscale < 0) + (*row)[i] = *(Q_LLONG*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale); + else + (*row)[i] = QVariant(*(Q_LLONG*)buf); + break; + case SQL_LONG: + if (sizeof(int) == sizeof(long)) //dear compiler: please optimize me out. + (*row)[i] = QVariant((int)(*(long*)buf)); + else + (*row)[i] = QVariant((Q_LLONG)(*(long*)buf)); + break; + case SQL_SHORT: + (*row)[i] = QVariant((int)(*(short*)buf)); + break; + case SQL_FLOAT: + (*row)[i] = QVariant((double)(*(float*)buf)); + break; + case SQL_DOUBLE: + (*row)[i] = QVariant(*(double*)buf); + break; + case SQL_TIMESTAMP: + (*row)[i] = toQDateTime((ISC_TIMESTAMP*)buf); + break; + case SQL_TYPE_TIME: + (*row)[i] = toQTime(*(ISC_TIME*)buf); + break; + case SQL_TYPE_DATE: + (*row)[i] = toQDate(*(ISC_DATE*)buf); + break; + case SQL_TEXT: + (*row)[i] = QString::fromUtf8(buf, size); + break; + case SQL_BLOB: + (*row)[i] = d->fetchBlob((ISC_QUAD*)buf); + break; + default: + // unknown type - don't even try to fetch + (*row)[i] = QVariant(); + break; + } + } + + return TRUE; +} + +int QIBaseResult::size() +{ + static char sizeInfo[] = {isc_info_sql_records}; + char buf[33]; + + if (!isActive() || !isSelect()) + return -1; + + isc_dsql_sql_info(d->status, &d->stmt, sizeof(sizeInfo), sizeInfo, sizeof(buf), buf); + for (char* c = buf + 3; *c != isc_info_end; /*nothing*/) { + char ct = *c++; + short len = isc_vax_integer(c, 2); + c += 2; + int val = isc_vax_integer(c, len); + c += len; + if (ct == isc_info_req_select_count) + return val; + } + return -1; +} + +int QIBaseResult::numRowsAffected() +{ + static char acCountInfo[] = {isc_info_sql_records}; + char cCountType; + + switch (d->queryType) { + case isc_info_sql_stmt_select: + cCountType = isc_info_req_select_count; + break; + case isc_info_sql_stmt_update: + cCountType = isc_info_req_update_count; + break; + case isc_info_sql_stmt_delete: + cCountType = isc_info_req_delete_count; + break; + case isc_info_sql_stmt_insert: + cCountType = isc_info_req_insert_count; + break; + } + + char acBuffer[33]; + int iResult = -1; + isc_dsql_sql_info(d->status, &d->stmt, sizeof(acCountInfo), acCountInfo, sizeof(acBuffer), acBuffer); + if (d->isError("Could not get statement info", QSqlError::Statement)) + return -1; + for (char *pcBuf = acBuffer + 3; *pcBuf != isc_info_end; /*nothing*/) { + char cType = *pcBuf++; + short sLength = isc_vax_integer (pcBuf, 2); + pcBuf += 2; + int iValue = isc_vax_integer (pcBuf, sLength); + pcBuf += sLength; + + if (cType == cCountType) { + iResult = iValue; + break; + } + } + return iResult; +} + +/*********************************/ + +QIBaseDriver::QIBaseDriver(QObject * parent, const char * name) + : QSqlDriver(parent, name ? name : QIBASE_DRIVER_NAME) +{ + d = new QIBaseDriverPrivate(this); +} + +QIBaseDriver::QIBaseDriver(void *connection, QObject *parent, const char *name) + : QSqlDriver(parent, name ? name : QIBASE_DRIVER_NAME) +{ + d = new QIBaseDriverPrivate(this); + d->ibase = (isc_db_handle)(long int)connection; + setOpen(TRUE); + setOpenError(FALSE); +} + +QIBaseDriver::~QIBaseDriver() +{ + delete d; +} + +bool QIBaseDriver::hasFeature(DriverFeature f) const +{ + switch (f) { + case Transactions: +// case QuerySize: + case PreparedQueries: + case PositionalPlaceholders: + case Unicode: + case BLOB: + return TRUE; + default: + return FALSE; + } +} + +bool QIBaseDriver::open(const QString & db, + const QString & user, + const QString & password, + const QString & host, + int /*port*/, + const QString & /* connOpts */) +{ + if (isOpen()) + close(); + + static const char enc[8] = "UTF_FSS"; + QCString usr = user.local8Bit(); + QCString pass = password.local8Bit(); + usr.truncate(255); + pass.truncate(255); + + QByteArray ba(usr.length() + pass.length() + sizeof(enc) + 6); + int i = -1; + ba[++i] = isc_dpb_version1; + ba[++i] = isc_dpb_user_name; + ba[++i] = usr.length(); + memcpy(&ba[++i], usr.data(), usr.length()); + i += usr.length(); + ba[i] = isc_dpb_password; + ba[++i] = pass.length(); + memcpy(&ba[++i], pass.data(), pass.length()); + i += pass.length(); + ba[i] = isc_dpb_lc_ctype; + ba[++i] = sizeof(enc) - 1; + memcpy(&ba[++i], enc, sizeof(enc) - 1); + i += sizeof(enc) - 1; + + QString ldb; + if (!host.isEmpty()) + ldb += host + ":"; + ldb += db; + isc_attach_database(d->status, 0, (char*)ldb.latin1(), &d->ibase, i, ba.data()); + if (d->isError("Error opening database", QSqlError::Connection)) { + setOpenError(TRUE); + return FALSE; + } + + setOpen(TRUE); + return TRUE; +} + +void QIBaseDriver::close() +{ + if (isOpen()) { + isc_detach_database(d->status, &d->ibase); + d->ibase = 0; + setOpen(FALSE); + setOpenError(FALSE); + } +} + +QSqlQuery QIBaseDriver::createQuery() const +{ + return QSqlQuery(new QIBaseResult(this)); +} + +bool QIBaseDriver::beginTransaction() +{ + if (!isOpen() || isOpenError()) + return FALSE; + if (d->trans) + return FALSE; + + isc_start_transaction(d->status, &d->trans, 1, &d->ibase, 0, NULL); + return !d->isError("Could not start transaction", QSqlError::Transaction); +} + +bool QIBaseDriver::commitTransaction() +{ + if (!isOpen() || isOpenError()) + return FALSE; + if (!d->trans) + return FALSE; + + isc_commit_transaction(d->status, &d->trans); + d->trans = 0; + return !d->isError("Unable to commit transaction", QSqlError::Transaction); +} + +bool QIBaseDriver::rollbackTransaction() +{ + if (!isOpen() || isOpenError()) + return FALSE; + if (!d->trans) + return FALSE; + + isc_rollback_transaction(d->status, &d->trans); + d->trans = 0; + return !d->isError("Unable to rollback transaction", QSqlError::Transaction); +} + +QStringList QIBaseDriver::tables(const QString& typeName) const +{ + QStringList res; + if (!isOpen()) + return res; + + int type = typeName.isEmpty() ? (int)QSql::Tables | (int)QSql::Views : typeName.toInt(); + QString typeFilter; + + if (type == (int)QSql::SystemTables) { + typeFilter += "RDB$SYSTEM_FLAG != 0"; + } else if (type == ((int)QSql::SystemTables | (int)QSql::Views)) { + typeFilter += "RDB$SYSTEM_FLAG != 0 OR RDB$VIEW_BLR NOT NULL"; + } else { + if (!(type & (int)QSql::SystemTables)) + typeFilter += "RDB$SYSTEM_FLAG = 0 AND "; + if (!(type & (int)QSql::Views)) + typeFilter += "RDB$VIEW_BLR IS NULL AND "; + if (!(type & (int)QSql::Tables)) + typeFilter += "RDB$VIEW_BLR IS NOT NULL AND "; + if (!typeFilter.isEmpty()) + typeFilter.truncate(typeFilter.length() - 5); + } + if (!typeFilter.isEmpty()) + typeFilter.prepend("where "); + + QSqlQuery q = createQuery(); + q.setForwardOnly(TRUE); + if (!q.exec("select rdb$relation_name from rdb$relations " + typeFilter)) + return res; + while(q.next()) + res << q.value(0).toString().stripWhiteSpace(); + + return res; +} + +QSqlRecord QIBaseDriver::record(const QString& tablename) const +{ + QSqlRecord rec; + if (!isOpen()) + return rec; + + QSqlQuery q = createQuery(); + q.setForwardOnly(TRUE); + + q.exec("SELECT a.RDB$FIELD_NAME, b.RDB$FIELD_TYPE " + "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b " + "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE " + "AND a.RDB$RELATION_NAME = '" + tablename.upper()+ "' " + "ORDER BY RDB$FIELD_POSITION"); + while (q.next()) { + QSqlField field(q.value(0).toString().stripWhiteSpace(), qIBaseTypeName(q.value(1).toInt())); + rec.append(field); + } + + return rec; +} + +QSqlRecordInfo QIBaseDriver::recordInfo(const QString& tablename) const +{ + QSqlRecordInfo rec; + if (!isOpen()) + return rec; + + QSqlQuery q = createQuery(); + q.setForwardOnly(TRUE); + + q.exec("SELECT a.RDB$FIELD_NAME, b.RDB$FIELD_TYPE, b.RDB$FIELD_LENGTH, b.RDB$FIELD_SCALE, " + "b.RDB$FIELD_PRECISION, a.RDB$NULL_FLAG " + "FROM RDB$RELATION_FIELDS a, RDB$FIELDS b " + "WHERE b.RDB$FIELD_NAME = a.RDB$FIELD_SOURCE " + "AND a.RDB$RELATION_NAME = '" + tablename.upper() + "' " + "ORDER BY a.RDB$FIELD_POSITION"); + + while (q.next()) { + QVariant::Type type = qIBaseTypeName(q.value(1).toInt()); + QSqlFieldInfo field(q.value(0).toString().stripWhiteSpace(), type, q.value(5).toInt(), + q.value(2).toInt(), q.value(4).toInt(), QVariant()); + + rec.append(field); + } + + return rec; +} + +QSqlIndex QIBaseDriver::primaryIndex(const QString &table) const +{ + QSqlIndex index(table); + if (!isOpen()) + return index; + + QSqlQuery q = createQuery(); + q.setForwardOnly(TRUE); + q.exec("SELECT a.RDB$INDEX_NAME, b.RDB$FIELD_NAME, d.RDB$FIELD_TYPE " + "FROM RDB$RELATION_CONSTRAINTS a, RDB$INDEX_SEGMENTS b, RDB$RELATION_FIELDS c, RDB$FIELDS d " + "WHERE a.RDB$CONSTRAINT_TYPE = 'PRIMARY KEY' " + "AND a.RDB$RELATION_NAME = '" + table.upper() + "' " + "AND a.RDB$INDEX_NAME = b.RDB$INDEX_NAME " + "AND c.RDB$RELATION_NAME = a.RDB$RELATION_NAME " + "AND c.RDB$FIELD_NAME = b.RDB$FIELD_NAME " + "AND d.RDB$FIELD_NAME = c.RDB$FIELD_SOURCE " + "ORDER BY b.RDB$FIELD_POSITION"); + + while (q.next()) { + QSqlField field(q.value(1).toString().stripWhiteSpace(), qIBaseTypeName(q.value(2).toInt())); + index.append(field); //TODO: asc? desc? + index.setName(q.value(0).toString()); + } + + return index; +} + +QSqlRecord QIBaseDriver::record(const QSqlQuery& query) const +{ + QSqlRecord rec; + if (query.isActive() && query.driver() == this) { + QIBaseResult* result = (QIBaseResult*)query.result(); + if (!result->d->sqlda) + return rec; + XSQLVAR v; + for (int i = 0; i < result->d->sqlda->sqld; ++i) { + v = result->d->sqlda->sqlvar[i]; + QSqlField f(QString::fromLatin1(v.sqlname, v.sqlname_length).stripWhiteSpace(), + qIBaseTypeName2(result->d->sqlda->sqlvar[i].sqltype)); + rec.append(f); + } + } + return rec; +} + +QSqlRecordInfo QIBaseDriver::recordInfo(const QSqlQuery& query) const +{ + QSqlRecordInfo rec; + if (query.isActive() && query.driver() == this) { + QIBaseResult* result = (QIBaseResult*)query.result(); + if (!result->d->sqlda) + return rec; + XSQLVAR v; + for (int i = 0; i < result->d->sqlda->sqld; ++i) { + v = result->d->sqlda->sqlvar[i]; + QSqlFieldInfo f(QString::fromLatin1(v.sqlname, v.sqlname_length).stripWhiteSpace(), + qIBaseTypeName2(result->d->sqlda->sqlvar[i].sqltype), + -1, v.sqllen, QABS(v.sqlscale), QVariant(), v.sqltype); + rec.append(f); + } + } + return rec; +} + +QString QIBaseDriver::formatValue(const QSqlField* field, bool trimStrings) const +{ + switch (field->type()) { + case QVariant::DateTime: { + QDateTime datetime = field->value().toDateTime(); + if (datetime.isValid()) + return "'" + QString::number(datetime.date().year()) + "-" + + QString::number(datetime.date().month()) + "-" + + QString::number(datetime.date().day()) + " " + + QString::number(datetime.time().hour()) + ":" + + QString::number(datetime.time().minute()) + ":" + + QString::number(datetime.time().second()) + "." + + QString::number(datetime.time().msec()).rightJustify(3, '0', TRUE) + "'"; + else + return "NULL"; + } + case QVariant::Time: { + QTime time = field->value().toTime(); + if (time.isValid()) + return "'" + QString::number(time.hour()) + ":" + + QString::number(time.minute()) + ":" + + QString::number(time.second()) + "." + + QString::number(time.msec()).rightJustify(3, '0', TRUE) + "'"; + else + return "NULL"; + } + case QVariant::Date: { + QDate date = field->value().toDate(); + if (date.isValid()) + return "'" + QString::number(date.year()) + "-" + + QString::number(date.month()) + "-" + + QString::number(date.day()) + "'"; + else + return "NULL"; + } + default: + return QSqlDriver::formatValue(field, trimStrings); + } +} diff --git a/main/dependencies/qt3/src/sql/drivers/ibase/qsql_ibase.h b/main/dependencies/qt3/src/sql/drivers/ibase/qsql_ibase.h new file mode 100644 index 000000000..563f50968 --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/ibase/qsql_ibase.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Definition of Interbase driver classes +** +** Created : 030911 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQL_IBASE_H +#define QSQL_IBASE_H + +#include "qsqlresult.h" +#include "qsqldriver.h" +#include "../cache/qsqlcachedresult.h" + + +class QIBaseDriverPrivate; +class QIBaseResultPrivate; +class QIBaseDriver; + +class QIBaseResult : public QtSqlCachedResult +{ + friend class QIBaseDriver; + friend class QIBaseResultPrivate; + +public: + QIBaseResult(const QIBaseDriver* db); + virtual ~QIBaseResult(); + + bool prepare(const QString& query); + bool exec(); + +protected: + bool gotoNext(QtSqlCachedResult::RowCache* row); + bool reset (const QString& query); + int size(); + int numRowsAffected(); + +private: + QIBaseResultPrivate* d; +}; + +class QIBaseDriver : public QSqlDriver +{ + friend class QIBaseDriverPrivate; + friend class QIBaseResultPrivate; + friend class QIBaseResult; +public: + QIBaseDriver(QObject *parent = 0, const char *name = 0); + QIBaseDriver(void *connection, QObject *parent = 0, const char *name = 0); + virtual ~QIBaseDriver(); + bool hasFeature(DriverFeature f) const; + bool open(const QString & db, + const QString & user, + const QString & password, + const QString & host, + int port, + const QString & connOpts); + bool open( const QString & db, + const QString & user, + const QString & password, + const QString & host, + int port ) { return open (db, user, password, host, port, QString()); } + void close(); + QSqlQuery createQuery() const; + bool beginTransaction(); + bool commitTransaction(); + bool rollbackTransaction(); + QStringList tables(const QString& typeName) const; + + QSqlRecord record(const QString& tablename) const; + QSqlRecordInfo recordInfo(const QString& tablename) const; + QSqlIndex primaryIndex(const QString &table) const; + QSqlRecord record(const QSqlQuery& query) const; + QSqlRecordInfo recordInfo(const QSqlQuery& query) const; + + QString formatValue(const QSqlField* field, bool trimStrings) const; + +private: + QIBaseDriverPrivate* d; +}; + + +#endif + diff --git a/main/dependencies/qt3/src/sql/drivers/mysql/qsql_mysql.cpp b/main/dependencies/qt3/src/sql/drivers/mysql/qsql_mysql.cpp new file mode 100644 index 000000000..7cfe0a748 --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/mysql/qsql_mysql.cpp @@ -0,0 +1,775 @@ +/**************************************************************************** +** +** Implementation of MYSQL driver classes +** +** Created : 001103 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsql_mysql.h" +#include <private/qsqlextension_p.h> + +#include <qdatetime.h> +#include <qvaluevector.h> +#include <qsqlrecord.h> + +#define QMYSQL_DRIVER_NAME "QMYSQL3" + +#ifdef Q_OS_WIN32 +// comment the next line out if you want to use MySQL/embedded on Win32 systems. +// note that it will crash if you don't statically link to the mysql/e library! +# define Q_NO_MYSQL_EMBEDDED +#endif + +QPtrDict<QSqlOpenExtension> *qSqlOpenExtDict(); + +static int qMySqlConnectionCount = 0; +static bool qMySqlInitHandledByUser = FALSE; + +class QMYSQLOpenExtension : public QSqlOpenExtension +{ +public: + QMYSQLOpenExtension( QMYSQLDriver *dri ) + : QSqlOpenExtension(), driver(dri) {} + ~QMYSQLOpenExtension() {} + + bool open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ); + +private: + QMYSQLDriver *driver; +}; + +bool QMYSQLOpenExtension::open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ) +{ + return driver->open( db, user, password, host, port, connOpts ); +} + +class QMYSQLDriverPrivate +{ +public: + QMYSQLDriverPrivate() : mysql(0) {} + MYSQL* mysql; +}; + +class QMYSQLResultPrivate : public QMYSQLDriverPrivate +{ +public: + QMYSQLResultPrivate() : QMYSQLDriverPrivate(), result(0) {} + MYSQL_RES* result; + MYSQL_ROW row; + QValueVector<QVariant::Type> fieldTypes; +}; + +QSqlError qMakeError( const QString& err, int type, const QMYSQLDriverPrivate* p ) +{ + return QSqlError(QMYSQL_DRIVER_NAME ": " + err, QString(mysql_error( p->mysql )), type, mysql_errno( p->mysql )); +} + +QVariant::Type qDecodeMYSQLType( int mysqltype, uint flags ) +{ + QVariant::Type type; + switch ( mysqltype ) { + case FIELD_TYPE_TINY : + case FIELD_TYPE_SHORT : + case FIELD_TYPE_LONG : + case FIELD_TYPE_INT24 : + type = (flags & UNSIGNED_FLAG) ? QVariant::UInt : QVariant::Int; + break; + case FIELD_TYPE_YEAR : + type = QVariant::Int; + break; + case FIELD_TYPE_LONGLONG : + type = (flags & UNSIGNED_FLAG) ? QVariant::ULongLong : QVariant::LongLong; + break; + case FIELD_TYPE_DECIMAL : + case FIELD_TYPE_FLOAT : + case FIELD_TYPE_DOUBLE : + type = QVariant::Double; + break; + case FIELD_TYPE_DATE : + type = QVariant::Date; + break; + case FIELD_TYPE_TIME : + type = QVariant::Time; + break; + case FIELD_TYPE_DATETIME : + case FIELD_TYPE_TIMESTAMP : + type = QVariant::DateTime; + break; + case FIELD_TYPE_BLOB : + case FIELD_TYPE_TINY_BLOB : + case FIELD_TYPE_MEDIUM_BLOB : + case FIELD_TYPE_LONG_BLOB : + type = (flags & BINARY_FLAG) ? QVariant::ByteArray : QVariant::CString; + break; + default: + case FIELD_TYPE_ENUM : + case FIELD_TYPE_SET : + case FIELD_TYPE_STRING : + case FIELD_TYPE_VAR_STRING : + type = QVariant::String; + break; + } + return type; +} + +QMYSQLResult::QMYSQLResult( const QMYSQLDriver* db ) +: QSqlResult( db ) +{ + d = new QMYSQLResultPrivate(); + d->mysql = db->d->mysql; +} + +QMYSQLResult::~QMYSQLResult() +{ + cleanup(); + delete d; +} + +MYSQL_RES* QMYSQLResult::result() +{ + return d->result; +} + +void QMYSQLResult::cleanup() +{ + if ( d->result ) { + mysql_free_result( d->result ); + } + d->result = NULL; + d->row = NULL; + setAt( -1 ); + setActive( FALSE ); +} + +bool QMYSQLResult::fetch( int i ) +{ + if ( isForwardOnly() ) { // fake a forward seek + if ( at() < i ) { + int x = i - at(); + while ( --x && fetchNext() ); + return fetchNext(); + } else { + return FALSE; + } + } + if ( at() == i ) + return TRUE; + mysql_data_seek( d->result, i ); + d->row = mysql_fetch_row( d->result ); + if ( !d->row ) + return FALSE; + setAt( i ); + return TRUE; +} + +bool QMYSQLResult::fetchNext() +{ + d->row = mysql_fetch_row( d->result ); + if ( !d->row ) + return FALSE; + setAt( at() + 1 ); + return TRUE; +} + +bool QMYSQLResult::fetchLast() +{ + if ( isForwardOnly() ) { // fake this since MySQL can't seek on forward only queries + bool success = fetchNext(); // did we move at all? + while ( fetchNext() ); + return success; + } + my_ulonglong numRows = mysql_num_rows( d->result ); + if ( !numRows ) + return FALSE; + return fetch( numRows - 1 ); +} + +bool QMYSQLResult::fetchFirst() +{ + if ( isForwardOnly() ) // again, fake it + return fetchNext(); + return fetch( 0 ); +} + +QVariant QMYSQLResult::data( int field ) +{ + if ( !isSelect() || field >= (int) d->fieldTypes.count() ) { + qWarning( "QMYSQLResult::data: column %d out of range", field ); + return QVariant(); + } + + QString val( d->row[field] ); + switch ( d->fieldTypes.at( field ) ) { + case QVariant::LongLong: + return QVariant( val.toLongLong() ); + case QVariant::ULongLong: + return QVariant( val.toULongLong() ); + case QVariant::Int: + return QVariant( val.toInt() ); + case QVariant::UInt: + return QVariant( val.toUInt() ); + case QVariant::Double: + return QVariant( val.toDouble() ); + case QVariant::Date: + if ( val.isEmpty() ) { + return QVariant( QDate() ); + } else { + return QVariant( QDate::fromString( val, Qt::ISODate ) ); + } + case QVariant::Time: + if ( val.isEmpty() ) { + return QVariant( QTime() ); + } else { + return QVariant( QTime::fromString( val, Qt::ISODate ) ); + } + case QVariant::DateTime: + if ( val.isEmpty() ) + return QVariant( QDateTime() ); + if ( val.length() == 14u ) + // TIMESTAMPS have the format yyyyMMddhhmmss + val.insert(4, "-").insert(7, "-").insert(10, 'T').insert(13, ':').insert(16, ':'); + return QVariant( QDateTime::fromString( val, Qt::ISODate ) ); + case QVariant::ByteArray: { + unsigned long* fl = mysql_fetch_lengths( d->result ); + QByteArray ba; + ba.duplicate( d->row[field], fl[field] ); + return QVariant( ba ); + } + default: + case QVariant::String: + case QVariant::CString: + return QVariant( val ); + } +#ifdef QT_CHECK_RANGE + qWarning("QMYSQLResult::data: unknown data type"); +#endif + return QVariant(); +} + +bool QMYSQLResult::isNull( int field ) +{ + if ( d->row[field] == NULL ) + return TRUE; + return FALSE; +} + +bool QMYSQLResult::reset ( const QString& query ) +{ + if ( !driver() ) + return FALSE; + if ( !driver()-> isOpen() || driver()->isOpenError() ) + return FALSE; + cleanup(); + + const char *encQuery = query.ascii(); + if ( mysql_real_query( d->mysql, encQuery, qstrlen(encQuery) ) ) { + setLastError( qMakeError("Unable to execute query", QSqlError::Statement, d ) ); + return FALSE; + } + if ( isForwardOnly() ) { + if ( isActive() || isValid() ) // have to empty the results from previous query + fetchLast(); + d->result = mysql_use_result( d->mysql ); + } else { + d->result = mysql_store_result( d->mysql ); + } + if ( !d->result && mysql_field_count( d->mysql ) > 0 ) { + setLastError( qMakeError( "Unable to store result", QSqlError::Statement, d ) ); + return FALSE; + } + int numFields = mysql_field_count( d->mysql ); + setSelect( !( numFields == 0) ); + d->fieldTypes.resize( numFields ); + if ( isSelect() ) { + for( int i = 0; i < numFields; i++) { + MYSQL_FIELD* field = mysql_fetch_field_direct( d->result, i ); + if ( field->type == FIELD_TYPE_DECIMAL ) + d->fieldTypes[i] = QVariant::String; + else + d->fieldTypes[i] = qDecodeMYSQLType( field->type, field->flags ); + } + } + setActive( TRUE ); + return TRUE; +} + +int QMYSQLResult::size() +{ + return isSelect() ? (int)mysql_num_rows( d->result ) : -1; +} + +int QMYSQLResult::numRowsAffected() +{ + return (int)mysql_affected_rows( d->mysql ); +} + +///////////////////////////////////////////////////////// +static void qServerEnd() +{ +#ifndef Q_NO_MYSQL_EMBEDDED +# if MYSQL_VERSION_ID >= 40000 + mysql_server_end(); +# endif // MYSQL_VERSION_ID +#endif // Q_NO_MYSQL_EMBEDDED +} + +static void qServerInit() +{ +#ifndef Q_NO_MYSQL_EMBEDDED +# if MYSQL_VERSION_ID >= 40000 + if ( qMySqlInitHandledByUser || qMySqlConnectionCount > 1 ) + return; + + // this should only be called once + // has no effect on client/server library + // but is vital for the embedded lib + if ( mysql_server_init( 0, 0, 0 ) ) { +# ifdef QT_CHECK_RANGE + qWarning( "QMYSQLDriver::qServerInit: unable to start server." ); +# endif + } + +# endif // MYSQL_VERSION_ID +#endif // Q_NO_MYSQL_EMBEDDED +} + +QMYSQLDriver::QMYSQLDriver( QObject * parent, const char * name ) + : QSqlDriver( parent, name ? name : QMYSQL_DRIVER_NAME ) +{ + init(); + qServerInit(); +} + +/*! + Create a driver instance with an already open connection handle. +*/ + +QMYSQLDriver::QMYSQLDriver( MYSQL * con, QObject * parent, const char * name ) + : QSqlDriver( parent, name ? name : QMYSQL_DRIVER_NAME ) +{ + init(); + if ( con ) { + d->mysql = (MYSQL *) con; + setOpen( TRUE ); + setOpenError( FALSE ); + if (qMySqlConnectionCount == 1) + qMySqlInitHandledByUser = TRUE; + } else { + qServerInit(); + } +} + +void QMYSQLDriver::init() +{ + qSqlOpenExtDict()->insert( this, new QMYSQLOpenExtension(this) ); + d = new QMYSQLDriverPrivate(); + d->mysql = 0; + qMySqlConnectionCount++; +} + +QMYSQLDriver::~QMYSQLDriver() +{ + qMySqlConnectionCount--; + if (qMySqlConnectionCount == 0 && !qMySqlInitHandledByUser) + qServerEnd(); + + delete d; + if ( !qSqlOpenExtDict()->isEmpty() ) { + QSqlOpenExtension *ext = qSqlOpenExtDict()->take( this ); + delete ext; + } +} + +bool QMYSQLDriver::hasFeature( DriverFeature f ) const +{ + switch ( f ) { + case Transactions: +// CLIENT_TRANSACTION should be defined in all recent mysql client libs > 3.23.34 +#ifdef CLIENT_TRANSACTIONS + if ( d->mysql ) { + if ( ( d->mysql->server_capabilities & CLIENT_TRANSACTIONS ) == CLIENT_TRANSACTIONS ) + return TRUE; + } +#endif + return FALSE; + case QuerySize: + return TRUE; + case BLOB: + return TRUE; + case Unicode: + return FALSE; + default: + return FALSE; + } +} + +bool QMYSQLDriver::open( const QString&, + const QString&, + const QString&, + const QString&, + int ) +{ + qWarning("QMYSQLDriver::open(): This version of open() is no longer supported." ); + return FALSE; +} + +bool QMYSQLDriver::open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ) +{ + if ( isOpen() ) + close(); + + unsigned int optionFlags = 0; + + QStringList raw = QStringList::split( ';', connOpts ); + QStringList opts; + QStringList::ConstIterator it; + + // extract the real options from the string + for ( it = raw.begin(); it != raw.end(); ++it ) { + QString tmp( *it ); + int idx; + if ( (idx = tmp.find( '=' )) != -1 ) { + QString val( tmp.mid( idx + 1 ) ); + val.simplifyWhiteSpace(); + if ( val == "TRUE" || val == "1" ) + opts << tmp.left( idx ); + else + qWarning( "QMYSQLDriver::open: Illegal connect option value '%s'", tmp.latin1() ); + } else { + opts << tmp; + } + } + + for ( it = opts.begin(); it != opts.end(); ++it ) { + QString opt( (*it).upper() ); + if ( opt == "CLIENT_COMPRESS" ) + optionFlags |= CLIENT_COMPRESS; + else if ( opt == "CLIENT_FOUND_ROWS" ) + optionFlags |= CLIENT_FOUND_ROWS; + else if ( opt == "CLIENT_IGNORE_SPACE" ) + optionFlags |= CLIENT_IGNORE_SPACE; + else if ( opt == "CLIENT_INTERACTIVE" ) + optionFlags |= CLIENT_INTERACTIVE; + else if ( opt == "CLIENT_NO_SCHEMA" ) + optionFlags |= CLIENT_NO_SCHEMA; + else if ( opt == "CLIENT_ODBC" ) + optionFlags |= CLIENT_ODBC; + else if ( opt == "CLIENT_SSL" ) + optionFlags |= CLIENT_SSL; + else + qWarning( "QMYSQLDriver::open: Unknown connect option '%s'", (*it).latin1() ); + } + + if ( (d->mysql = mysql_init((MYSQL*) 0)) && + mysql_real_connect( d->mysql, + host, + user, + password, + db.isNull() ? QString("") : db, + (port > -1) ? port : 0, + NULL, + optionFlags ) ) + { + if ( !db.isEmpty() && mysql_select_db( d->mysql, db )) { + setLastError( qMakeError("Unable open database '" + db + "'", QSqlError::Connection, d ) ); + mysql_close( d->mysql ); + setOpenError( TRUE ); + return FALSE; + } + } else { + setLastError( qMakeError( "Unable to connect", QSqlError::Connection, d ) ); + mysql_close( d->mysql ); + setOpenError( TRUE ); + return FALSE; + } + setOpen( TRUE ); + setOpenError( FALSE ); + return TRUE; +} + +void QMYSQLDriver::close() +{ + if ( isOpen() ) { + mysql_close( d->mysql ); + setOpen( FALSE ); + setOpenError( FALSE ); + } +} + +QSqlQuery QMYSQLDriver::createQuery() const +{ + return QSqlQuery( new QMYSQLResult( this ) ); +} + +QStringList QMYSQLDriver::tables( const QString& typeName ) const +{ + QStringList tl; + if ( !isOpen() ) + return tl; + if ( !typeName.isEmpty() && !(typeName.toInt() & (int)QSql::Tables) ) + return tl; + + MYSQL_RES* tableRes = mysql_list_tables( d->mysql, NULL ); + MYSQL_ROW row; + int i = 0; + while ( tableRes && TRUE ) { + mysql_data_seek( tableRes, i ); + row = mysql_fetch_row( tableRes ); + if ( !row ) + break; + tl.append( QString(row[0]) ); + i++; + } + mysql_free_result( tableRes ); + return tl; +} + +QSqlIndex QMYSQLDriver::primaryIndex( const QString& tablename ) const +{ + QSqlIndex idx; + if ( !isOpen() ) + return idx; + QSqlQuery i = createQuery(); + QString stmt( "show index from %1;" ); + QSqlRecord fil = record( tablename ); + i.exec( stmt.arg( tablename ) ); + while ( i.isActive() && i.next() ) { + if ( i.value(2).toString() == "PRIMARY" ) { + idx.append( *fil.field( i.value(4).toString() ) ); + idx.setCursorName( i.value(0).toString() ); + idx.setName( i.value(2).toString() ); + } + } + return idx; +} + +QSqlRecord QMYSQLDriver::record( const QString& tablename ) const +{ + QSqlRecord fil; + if ( !isOpen() ) + return fil; + MYSQL_RES* r = mysql_list_fields( d->mysql, tablename.local8Bit().data(), 0); + if ( !r ) { + return fil; + } + MYSQL_FIELD* field; + while ( (field = mysql_fetch_field( r ))) { + QSqlField f ( QString( field->name ) , qDecodeMYSQLType( (int)field->type, field->flags ) ); + fil.append ( f ); + } + mysql_free_result( r ); + return fil; +} + +QSqlRecord QMYSQLDriver::record( const QSqlQuery& query ) const +{ + QSqlRecord fil; + if ( !isOpen() ) + return fil; + if ( query.isActive() && query.isSelect() && query.driver() == this ) { + QMYSQLResult* result = (QMYSQLResult*)query.result(); + QMYSQLResultPrivate* p = result->d; + if ( !mysql_errno( p->mysql ) ) { + for ( ;; ) { + MYSQL_FIELD* f = mysql_fetch_field( p->result ); + if ( f ) { + QSqlField fi( QString((const char*)f->name), qDecodeMYSQLType( f->type, f->flags ) ); + fil.append( fi ); + } else + break; + } + } + mysql_field_seek( p->result, 0 ); + } + return fil; +} + +QSqlRecordInfo QMYSQLDriver::recordInfo( const QString& tablename ) const +{ + QSqlRecordInfo info; + if ( !isOpen() ) + return info; + MYSQL_RES* r = mysql_list_fields( d->mysql, tablename.local8Bit().data(), 0); + if ( !r ) { + return info; + } + MYSQL_FIELD* field; + while ( (field = mysql_fetch_field( r ))) { + info.append ( QSqlFieldInfo( QString( field->name ), + qDecodeMYSQLType( (int)field->type, field->flags ), + IS_NOT_NULL( field->flags ), + (int)field->length, + (int)field->decimals, + QString( field->def ), + (int)field->type ) ); + } + mysql_free_result( r ); + return info; +} + +QSqlRecordInfo QMYSQLDriver::recordInfo( const QSqlQuery& query ) const +{ + QSqlRecordInfo info; + if ( !isOpen() ) + return info; + if ( query.isActive() && query.isSelect() && query.driver() == this ) { + QMYSQLResult* result = (QMYSQLResult*)query.result(); + QMYSQLResultPrivate* p = result->d; + if ( !mysql_errno( p->mysql ) ) { + for ( ;; ) { + MYSQL_FIELD* field = mysql_fetch_field( p->result ); + if ( field ) { + info.append ( QSqlFieldInfo( QString( field->name ), + qDecodeMYSQLType( (int)field->type, field->flags ), + IS_NOT_NULL( field->flags ), + (int)field->length, + (int)field->decimals, + QVariant(), + (int)field->type ) ); + + } else + break; + } + } + mysql_field_seek( p->result, 0 ); + } + return info; +} + +MYSQL* QMYSQLDriver::mysql() +{ + return d->mysql; +} + +bool QMYSQLDriver::beginTransaction() +{ +#ifndef CLIENT_TRANSACTIONS + return FALSE; +#endif + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + qWarning( "QMYSQLDriver::beginTransaction: Database not open" ); +#endif + return FALSE; + } + if ( mysql_query( d->mysql, "BEGIN WORK" ) ) { + setLastError( qMakeError("Unable to begin transaction", QSqlError::Statement, d ) ); + return FALSE; + } + return TRUE; +} + +bool QMYSQLDriver::commitTransaction() +{ +#ifndef CLIENT_TRANSACTIONS + return FALSE; +#endif + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + qWarning( "QMYSQLDriver::commitTransaction: Database not open" ); +#endif + return FALSE; + } + if ( mysql_query( d->mysql, "COMMIT" ) ) { + setLastError( qMakeError("Unable to commit transaction", QSqlError::Statement, d ) ); + return FALSE; + } + return TRUE; +} + +bool QMYSQLDriver::rollbackTransaction() +{ +#ifndef CLIENT_TRANSACTIONS + return FALSE; +#endif + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + qWarning( "QMYSQLDriver::rollbackTransaction: Database not open" ); +#endif + return FALSE; + } + if ( mysql_query( d->mysql, "ROLLBACK" ) ) { + setLastError( qMakeError("Unable to rollback transaction", QSqlError::Statement, d ) ); + return FALSE; + } + return TRUE; +} + +QString QMYSQLDriver::formatValue( const QSqlField* field, bool trimStrings ) const +{ + QString r; + if ( field->isNull() ) { + r = nullText(); + } else { + switch( field->type() ) { + case QVariant::ByteArray: { + + const QByteArray ba = field->value().toByteArray(); + // buffer has to be at least length*2+1 bytes + char* buffer = new char[ ba.size() * 2 + 1 ]; + /*uint escapedSize =*/ mysql_escape_string( buffer, ba.data(), ba.size() ); + r.append("'").append(buffer).append("'"); + delete[] buffer; + } + break; + case QVariant::String: + case QVariant::CString: { + // Escape '\' characters + r = QSqlDriver::formatValue( field ); + r.replace( "\\", "\\\\" ); + break; + } + default: + r = QSqlDriver::formatValue( field, trimStrings ); + } + } + return r; +} diff --git a/main/dependencies/qt3/src/sql/drivers/mysql/qsql_mysql.h b/main/dependencies/qt3/src/sql/drivers/mysql/qsql_mysql.h new file mode 100644 index 000000000..ff8ace67d --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/mysql/qsql_mysql.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Definition of MySQL driver classes +** +** Created : 001103 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQL_MYSQL_H +#define QSQL_MYSQL_H + +#include <qsqldriver.h> +#include <qsqlresult.h> +#include <qsqlfield.h> +#include <qsqlindex.h> + +#if defined (Q_OS_WIN32) +#include <qt_windows.h> +#endif + +#include <mysql.h> + +#ifdef QT_PLUGIN +#define Q_EXPORT_SQLDRIVER_MYSQL +#else +#define Q_EXPORT_SQLDRIVER_MYSQL Q_EXPORT +#endif + +class QMYSQLDriverPrivate; +class QMYSQLResultPrivate; +class QMYSQLDriver; +class QSqlRecordInfo; + +class QMYSQLResult : public QSqlResult +{ + friend class QMYSQLDriver; +public: + QMYSQLResult( const QMYSQLDriver* db ); + ~QMYSQLResult(); + + MYSQL_RES* result(); +protected: + void cleanup(); + bool fetch( int i ); + bool fetchNext(); + bool fetchLast(); + bool fetchFirst(); + QVariant data( int field ); + bool isNull( int field ); + bool reset ( const QString& query ); + int size(); + int numRowsAffected(); +private: + QMYSQLResultPrivate* d; +}; + +class Q_EXPORT_SQLDRIVER_MYSQL QMYSQLDriver : public QSqlDriver +{ + friend class QMYSQLResult; +public: + QMYSQLDriver( QObject * parent=0, const char * name=0 ); + QMYSQLDriver( MYSQL * con, QObject * parent=0, const char * name=0 ); + ~QMYSQLDriver(); + bool hasFeature( DriverFeature f ) const; + bool open( const QString & db, + const QString & user = QString::null, + const QString & password = QString::null, + const QString & host = QString::null, + int port = -1 ); + void close(); + QSqlQuery createQuery() const; + QStringList tables( const QString& user ) const; + QSqlIndex primaryIndex( const QString& tablename ) const; + QSqlRecord record( const QString& tablename ) const; + QSqlRecord record( const QSqlQuery& query ) const; + QSqlRecordInfo recordInfo( const QString& tablename ) const; + QSqlRecordInfo recordInfo( const QSqlQuery& query ) const; + QString formatValue( const QSqlField* field, + bool trimStrings ) const; + MYSQL* mysql(); + // ### remove me for 4.0 + bool open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ); + +protected: + bool beginTransaction(); + bool commitTransaction(); + bool rollbackTransaction(); +private: + void init(); + QMYSQLDriverPrivate* d; +}; + + +#endif diff --git a/main/dependencies/qt3/src/sql/drivers/odbc/debian_qsql_odbc.h b/main/dependencies/qt3/src/sql/drivers/odbc/debian_qsql_odbc.h new file mode 100644 index 000000000..4b91f475c --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/odbc/debian_qsql_odbc.h @@ -0,0 +1,10 @@ +#ifdef UNICODE +typedef SQLWCHAR SQLTCHAR; +#else +typedef SQLCHAR SQLTCHAR; +#endif + +#define SQL_WCHAR (-8) +#define SQL_WVARCHAR (-9) +#define SQL_WLONGVARCHAR (-10) +#define SQL_C_WCHAR SQL_WCHAR diff --git a/main/dependencies/qt3/src/sql/drivers/odbc/qsql_odbc.cpp b/main/dependencies/qt3/src/sql/drivers/odbc/qsql_odbc.cpp new file mode 100644 index 000000000..b09afd242 --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/odbc/qsql_odbc.cpp @@ -0,0 +1,2035 @@ +/**************************************************************************** +** +** Implementation of ODBC driver classes +** +** Created : 001103 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsql_odbc.h" +#include <qsqlrecord.h> + +#if defined (Q_OS_WIN32) +#include <qt_windows.h> +#include <qapplication.h> +#endif +#include <qdatetime.h> +#include <private/qsqlextension_p.h> +#include <private/qinternal_p.h> +#include <stdlib.h> + +// undefine this to prevent initial check of the ODBC driver +#define ODBC_CHECK_DRIVER + +#if defined(Q_ODBC_VERSION_2) +//crude hack to get non-unicode capable driver managers to work +# undef UNICODE +# define SQLTCHAR SQLCHAR +# define SQL_C_WCHAR SQL_C_CHAR +#endif + +// newer platform SDKs use SQLLEN instead of SQLINTEGER +#ifdef SQLLEN +# define QSQLLEN SQLLEN +#else +# define QSQLLEN SQLINTEGER +#endif + +#ifdef SQLULEN +# define QSQLULEN SQLULEN +#else +# define QSQLULEN SQLUINTEGER +#endif + + +static const QSQLLEN COLNAMESIZE = 256; +//Map Qt parameter types to ODBC types +static const SQLSMALLINT qParamType[ 4 ] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT }; + +class QODBCPrivate +{ +public: + QODBCPrivate() + : hEnv(0), hDbc(0), hStmt(0), useSchema(FALSE) + { + sql_char_type = sql_varchar_type = sql_longvarchar_type = QVariant::CString; + unicode = FALSE; + } + + SQLHANDLE hEnv; + SQLHANDLE hDbc; + SQLHANDLE hStmt; + + bool unicode; + bool useSchema; + QVariant::Type sql_char_type; + QVariant::Type sql_varchar_type; + QVariant::Type sql_longvarchar_type; + + QSqlRecordInfo rInf; + + bool checkDriver() const; + void checkUnicode(); + void checkSchemaUsage(); + bool setConnectionOptions( const QString& connOpts ); + void splitTableQualifier(const QString &qualifier, QString &catalog, + QString &schema, QString &table); +}; + +class QODBCPreparedExtension : public QSqlExtension +{ +public: + QODBCPreparedExtension( QODBCResult * r ) + : result( r ) {} + + bool prepare( const QString& query ) + { + return result->prepare( query ); + } + + bool exec() + { + return result->exec(); + } + + QODBCResult * result; +}; + +QPtrDict<QSqlOpenExtension> *qSqlOpenExtDict(); + +class QODBCOpenExtension : public QSqlOpenExtension +{ +public: + QODBCOpenExtension( QODBCDriver *dri ) + : QSqlOpenExtension(), driver(dri) {} + ~QODBCOpenExtension() {} + + bool open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ); +private: + QODBCDriver *driver; +}; + +bool QODBCOpenExtension::open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ) +{ + return driver->open( db, user, password, host, port, connOpts ); +} + +static QString qWarnODBCHandle(int handleType, SQLHANDLE handle) +{ + SQLINTEGER nativeCode_; + SQLSMALLINT msgLen; + SQLRETURN r = SQL_ERROR; + SQLTCHAR state_[SQL_SQLSTATE_SIZE+1]; + SQLTCHAR description_[SQL_MAX_MESSAGE_LENGTH]; + r = SQLGetDiagRec( handleType, + handle, + 1, + (SQLTCHAR*)state_, + &nativeCode_, + (SQLTCHAR*)description_, + SQL_MAX_MESSAGE_LENGTH-1, /* in bytes, not in characters */ + &msgLen); + if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) +#ifdef UNICODE + return QString( (const QChar*)description_, (uint)msgLen ); +#else + return QString::fromLocal8Bit( (const char*)description_ ); +#endif + return QString::null; +} + +static QString qODBCWarn( const QODBCPrivate* odbc) +{ + return ( qWarnODBCHandle( SQL_HANDLE_ENV, odbc->hEnv ) + " " + + qWarnODBCHandle( SQL_HANDLE_DBC, odbc->hDbc ) + " " + + qWarnODBCHandle( SQL_HANDLE_STMT, odbc->hStmt ) ); +} + +static void qSqlWarning( const QString& message, const QODBCPrivate* odbc ) +{ +#ifdef QT_CHECK_RANGE + qWarning( "%s\tError: %s", message.local8Bit().data(), qODBCWarn( odbc ).local8Bit().data() ); +#endif +} + +static QSqlError qMakeError( const QString& err, int type, const QODBCPrivate* p ) +{ + return QSqlError( "QODBC3: " + err, qODBCWarn(p), type ); +} + +static QVariant::Type qDecodeODBCType( SQLSMALLINT sqltype, const QODBCPrivate* p ) +{ + QVariant::Type type = QVariant::Invalid; + switch ( sqltype ) { + case SQL_DECIMAL: + case SQL_NUMERIC: + case SQL_REAL: + case SQL_FLOAT: + case SQL_DOUBLE: + type = QVariant::Double; + break; + case SQL_SMALLINT: + case SQL_INTEGER: + case SQL_BIT: + case SQL_TINYINT: + type = QVariant::Int; + break; + case SQL_BIGINT: + type = QVariant::LongLong; + break; + case SQL_BINARY: + case SQL_VARBINARY: + case SQL_LONGVARBINARY: + type = QVariant::ByteArray; + break; + case SQL_DATE: + case SQL_TYPE_DATE: + type = QVariant::Date; + break; + case SQL_TIME: + case SQL_TYPE_TIME: + type = QVariant::Time; + break; + case SQL_TIMESTAMP: + case SQL_TYPE_TIMESTAMP: + type = QVariant::DateTime; + break; +#ifndef Q_ODBC_VERSION_2 + case SQL_WCHAR: + case SQL_WVARCHAR: + case SQL_WLONGVARCHAR: + type = QVariant::String; + break; +#endif + case SQL_CHAR: + type = p->sql_char_type; + break; + case SQL_VARCHAR: + type = p->sql_varchar_type; + break; + case SQL_LONGVARCHAR: + type = p->sql_longvarchar_type; + break; + default: + type = QVariant::CString; + break; + } + return type; +} + +static QString qGetStringData( SQLHANDLE hStmt, int column, int colSize, bool& isNull, bool unicode = FALSE ) +{ + QString fieldVal; + SQLRETURN r = SQL_ERROR; + QSQLLEN lengthIndicator = 0; + + if ( colSize <= 0 ) { + colSize = 256; + } else if ( colSize > 65536 ) { // limit buffer size to 64 KB + colSize = 65536; + } else { + colSize++; // make sure there is room for more than the 0 termination + if ( unicode ) { + colSize *= 2; // a tiny bit faster, since it saves a SQLGetData() call + } + } + char* buf = new char[ colSize ]; + while ( TRUE ) { + r = SQLGetData( hStmt, + column+1, + unicode ? SQL_C_WCHAR : SQL_C_CHAR, + (SQLPOINTER)buf, + (QSQLLEN)colSize, + &lengthIndicator ); + if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) { + if ( lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL ) { + fieldVal = QString::null; + isNull = TRUE; + break; + } + // if SQL_SUCCESS_WITH_INFO is returned, indicating that + // more data can be fetched, the length indicator does NOT + // contain the number of bytes returned - it contains the + // total number of bytes that CAN be fetched + // colSize-1: remove 0 termination when there is more data to fetch + int rSize = (r == SQL_SUCCESS_WITH_INFO) ? (unicode ? colSize-2 : colSize-1) : lengthIndicator; + if ( unicode ) { + fieldVal += QString( (QChar*) buf, rSize / 2 ); + } else { + buf[ rSize ] = 0; + fieldVal += buf; + } + if ( lengthIndicator < colSize ) { + // workaround for Drivermanagers that don't return SQL_NO_DATA + break; + } + } else if ( r == SQL_NO_DATA ) { + break; + } else { +#ifdef QT_CHECK_RANGE + qWarning( "qGetStringData: Error while fetching data (%d)", r ); +#endif + fieldVal = QString::null; + break; + } + } + delete[] buf; + return fieldVal; +} + +static QByteArray qGetBinaryData( SQLHANDLE hStmt, int column, QSQLLEN& lengthIndicator, bool& isNull ) +{ + QByteArray fieldVal; + SQLSMALLINT colNameLen; + SQLSMALLINT colType; + QSQLULEN colSize; + SQLSMALLINT colScale; + SQLSMALLINT nullable; + SQLRETURN r = SQL_ERROR; + + SQLTCHAR colName[COLNAMESIZE]; + r = SQLDescribeCol( hStmt, + column+1, + colName, + COLNAMESIZE, + &colNameLen, + &colType, + &colSize, + &colScale, + &nullable ); +#ifdef QT_CHECK_RANGE + if ( r != SQL_SUCCESS ) + qWarning( "qGetBinaryData: Unable to describe column %d", column ); +#endif + // SQLDescribeCol may return 0 if size cannot be determined + if (!colSize) { + colSize = 256; + } + if ( colSize > 65536 ) { // read the field in 64 KB chunks + colSize = 65536; + } + char * buf = new char[ colSize ]; + while ( TRUE ) { + r = SQLGetData( hStmt, + column+1, + SQL_C_BINARY, + (SQLPOINTER) buf, + (QSQLLEN)colSize, + &lengthIndicator ); + if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) { + if ( lengthIndicator == SQL_NULL_DATA ) { + isNull = TRUE; + break; + } else { + int rSize; + r == SQL_SUCCESS ? rSize = lengthIndicator : rSize = colSize; + if ( lengthIndicator == SQL_NO_TOTAL ) { // size cannot be determined + rSize = colSize; + } + // NB! This is not a memleak - the mem will be deleted by QByteArray when + // no longer ref'd + char * tmp = (char *) malloc( rSize + fieldVal.size() ); + if ( fieldVal.size() ) { + memcpy( tmp, fieldVal.data(), fieldVal.size() ); + } + memcpy( tmp + fieldVal.size(), buf, rSize ); + fieldVal = fieldVal.assign( tmp, fieldVal.size() + rSize ); + + if ( r == SQL_SUCCESS ) { // the whole field was read in one chunk + break; + } + } + } else { + break; + } + } + delete [] buf; + return fieldVal; +} + +static int qGetIntData( SQLHANDLE hStmt, int column, bool& isNull ) +{ + QSQLLEN intbuf = 0; + isNull = FALSE; + QSQLLEN lengthIndicator = 0; + SQLRETURN r = SQLGetData( hStmt, + column+1, + SQL_C_SLONG, + (SQLPOINTER)&intbuf, + (QSQLLEN)0, + &lengthIndicator ); + if ( ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) || lengthIndicator == SQL_NULL_DATA ) { + isNull = TRUE; + return 0; + } + return (int)intbuf; +} + +static double qGetDoubleData( SQLHANDLE hStmt, int column, bool& isNull ) +{ + SQLDOUBLE dblbuf; + QSQLLEN lengthIndicator = 0; + isNull = FALSE; + SQLRETURN r = SQLGetData( hStmt, + column+1, + SQL_C_DOUBLE, + (SQLPOINTER)&dblbuf, + (QSQLLEN)0, + &lengthIndicator ); + if ( ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) || lengthIndicator == SQL_NULL_DATA ) { + isNull = TRUE; + return 0.0; + } + + return (double) dblbuf; +} + +static SQLBIGINT qGetBigIntData( SQLHANDLE hStmt, int column, bool& isNull ) +{ + SQLBIGINT lngbuf = Q_INT64_C( 0 ); + isNull = FALSE; + QSQLLEN lengthIndicator = 0; + SQLRETURN r = SQLGetData( hStmt, + column+1, + SQL_C_SBIGINT, + (SQLPOINTER) &lngbuf, + (QSQLLEN)0, + &lengthIndicator ); + if ( ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) || lengthIndicator == SQL_NULL_DATA ) + isNull = TRUE; + + return lngbuf; +} + +// creates a QSqlFieldInfo from a valid hStmt generated +// by SQLColumns. The hStmt has to point to a valid position. +static QSqlFieldInfo qMakeFieldInfo( const SQLHANDLE hStmt, const QODBCPrivate* p ) +{ + bool isNull; + QString fname = qGetStringData( hStmt, 3, -1, isNull, p->unicode ); + int type = qGetIntData( hStmt, 4, isNull ); // column type + int required = qGetIntData( hStmt, 10, isNull ); // nullable-flag + // required can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN + if ( required == SQL_NO_NULLS ) { + required = 1; + } else if ( required == SQL_NULLABLE ) { + required = 0; + } else { + required = -1; + } + int size = qGetIntData( hStmt, 6, isNull ); // column size + int prec = qGetIntData( hStmt, 8, isNull ); // precision + return QSqlFieldInfo( fname, qDecodeODBCType( type, p ), required, size, prec, QVariant(), type ); +} + +static QSqlFieldInfo qMakeFieldInfo( const QODBCPrivate* p, int i ) +{ + SQLSMALLINT colNameLen; + SQLSMALLINT colType; + QSQLULEN colSize; + SQLSMALLINT colScale; + SQLSMALLINT nullable; + SQLRETURN r = SQL_ERROR; + SQLTCHAR colName[ COLNAMESIZE ]; + r = SQLDescribeCol( p->hStmt, + i+1, + colName, + (QSQLULEN)COLNAMESIZE, + &colNameLen, + &colType, + &colSize, + &colScale, + &nullable); + + if ( r != SQL_SUCCESS ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( QString("qMakeField: Unable to describe column %1").arg(i), p ); +#endif + return QSqlFieldInfo(); + } +#ifdef UNICODE + QString qColName( (const QChar*)colName, (uint)colNameLen ); +#else + QString qColName = QString::fromLocal8Bit( (const char*)colName ); +#endif + // nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN + int required = -1; + if ( nullable == SQL_NO_NULLS ) { + required = 1; + } else if ( nullable == SQL_NULLABLE ) { + required = 0; + } + QVariant::Type type = qDecodeODBCType( colType, p ); + return QSqlFieldInfo( qColName, + type, + required, + (int)colSize == 0 ? -1 : (int)colSize, + (int)colScale == 0 ? -1 : (int)colScale, + QVariant(), + (int)colType ); +} + +bool QODBCPrivate::setConnectionOptions( const QString& connOpts ) +{ + // Set any connection attributes + QStringList raw = QStringList::split( ';', connOpts ); + QStringList opts; + SQLRETURN r = SQL_SUCCESS; + QMap<QString, QString> connMap; + for ( QStringList::ConstIterator it = raw.begin(); it != raw.end(); ++it ) { + QString tmp( *it ); + int idx; + if ( (idx = tmp.find( '=' )) != -1 ) + connMap[ tmp.left( idx ) ] = tmp.mid( idx + 1 ).simplifyWhiteSpace(); + else + qWarning( "QODBCDriver::open: Illegal connect option value '%s'", tmp.latin1() ); + } + if ( connMap.count() ) { + QMap<QString, QString>::ConstIterator it; + QString opt, val; + SQLUINTEGER v = 0; + for ( it = connMap.begin(); it != connMap.end(); ++it ) { + opt = it.key().upper(); + val = it.data().upper(); + r = SQL_SUCCESS; + if ( opt == "SQL_ATTR_ACCESS_MODE" ) { + if ( val == "SQL_MODE_READ_ONLY" ) { + v = SQL_MODE_READ_ONLY; + } else if ( val == "SQL_MODE_READ_WRITE" ) { + v = SQL_MODE_READ_WRITE; + } else { + qWarning( QString( "QODBCDriver::open: Unknown option value '%1'" ).arg( *it ) ); + break; + } + r = SQLSetConnectAttr( hDbc, SQL_ATTR_ACCESS_MODE, (SQLPOINTER) v, 0 ); + } else if ( opt == "SQL_ATTR_CONNECTION_TIMEOUT" ) { + v = val.toUInt(); + r = SQLSetConnectAttr( hDbc, SQL_ATTR_CONNECTION_TIMEOUT, (SQLPOINTER) v, 0 ); + } else if ( opt == "SQL_ATTR_LOGIN_TIMEOUT" ) { + v = val.toUInt(); + r = SQLSetConnectAttr( hDbc, SQL_ATTR_LOGIN_TIMEOUT, (SQLPOINTER) v, 0 ); + } else if ( opt == "SQL_ATTR_CURRENT_CATALOG" ) { + val.ucs2(); // 0 terminate + r = SQLSetConnectAttr( hDbc, SQL_ATTR_CURRENT_CATALOG, +#ifdef UNICODE + (SQLWCHAR*) val.unicode(), +#else + (SQLCHAR*) val.latin1(), +#endif + SQL_NTS ); + } else if ( opt == "SQL_ATTR_METADATA_ID" ) { + if ( val == "SQL_TRUE" ) { + v = SQL_TRUE; + } else if ( val == "SQL_FALSE" ) { + v = SQL_FALSE; + } else { + qWarning( QString( "QODBCDriver::open: Unknown option value '%1'" ).arg( *it ) ); + break; + } + r = SQLSetConnectAttr( hDbc, SQL_ATTR_METADATA_ID, (SQLPOINTER) v, 0 ); + } else if ( opt == "SQL_ATTR_PACKET_SIZE" ) { + v = val.toUInt(); + r = SQLSetConnectAttr( hDbc, SQL_ATTR_PACKET_SIZE, (SQLPOINTER) v, 0 ); + } else if ( opt == "SQL_ATTR_TRACEFILE" ) { + val.ucs2(); // 0 terminate + r = SQLSetConnectAttr( hDbc, SQL_ATTR_TRACEFILE, +#ifdef UNICODE + (SQLWCHAR*) val.unicode(), +#else + (SQLCHAR*) val.latin1(), +#endif + SQL_NTS ); + } else if ( opt == "SQL_ATTR_TRACE" ) { + if ( val == "SQL_OPT_TRACE_OFF" ) { + v = SQL_OPT_TRACE_OFF; + } else if ( val == "SQL_OPT_TRACE_ON" ) { + v = SQL_OPT_TRACE_ON; + } else { + qWarning( QString( "QODBCDriver::open: Unknown option value '%1'" ).arg( *it ) ); + break; + } + r = SQLSetConnectAttr( hDbc, SQL_ATTR_TRACE, (SQLPOINTER) v, 0 ); + } +#ifdef QT_CHECK_RANGE + else { + qWarning( QString("QODBCDriver::open: Unknown connection attribute '%1'").arg( opt ) ); + } +#endif + if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( QString("QODBCDriver::open: Unable to set connection attribute '%1'").arg( opt ), this ); +#endif + return FALSE; + } + } + } + return TRUE; +} + +void QODBCPrivate::splitTableQualifier(const QString & qualifier, QString &catalog, + QString &schema, QString &table) +{ + if (!useSchema) { + table = qualifier; + return; + } + QStringList l = QStringList::split( ".", qualifier, TRUE ); + if ( l.count() > 3 ) + return; // can't possibly be a valid table qualifier + int i = 0, n = l.count(); + if ( n == 1 ) { + table = qualifier; + } else { + for ( QStringList::Iterator it = l.begin(); it != l.end(); ++it ) { + if ( n == 3 ) { + if ( i == 0 ) { + catalog = *it; + } else if ( i == 1 ) { + schema = *it; + } else if ( i == 2 ) { + table = *it; + } + } else if ( n == 2 ) { + if ( i == 0 ) { + schema = *it; + } else if ( i == 1 ) { + table = *it; + } + } + i++; + } + } +} + +//////////////////////////////////////////////////////////////////////////// + +QODBCResult::QODBCResult( const QODBCDriver * db, QODBCPrivate* p ) +: QSqlResult(db) +{ + d = new QODBCPrivate(); + (*d) = (*p); + setExtension( new QODBCPreparedExtension( this ) ); +} + +QODBCResult::~QODBCResult() +{ + if ( d->hStmt && driver()->isOpen() ) { + SQLRETURN r = SQLFreeHandle( SQL_HANDLE_STMT, d->hStmt ); +#ifdef QT_CHECK_RANGE + if ( r != SQL_SUCCESS ) + qSqlWarning( "QODBCDriver: Unable to free statement handle " + QString::number(r), d ); +#endif + } + + delete d; +} + +bool QODBCResult::reset ( const QString& query ) +{ + setActive( FALSE ); + setAt( QSql::BeforeFirst ); + SQLRETURN r; + + d->rInf.clear(); + // Always reallocate the statement handle - the statement attributes + // are not reset if SQLFreeStmt() is called which causes some problems. + if ( d->hStmt ) { + r = SQLFreeHandle( SQL_HANDLE_STMT, d->hStmt ); + if ( r != SQL_SUCCESS ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCResult::reset: Unable to free statement handle", d ); +#endif + return FALSE; + } + } + r = SQLAllocHandle( SQL_HANDLE_STMT, + d->hDbc, + &d->hStmt ); + if ( r != SQL_SUCCESS ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCResult::reset: Unable to allocate statement handle", d ); +#endif + return FALSE; + } + + if ( isForwardOnly() ) { + r = SQLSetStmtAttr( d->hStmt, + SQL_ATTR_CURSOR_TYPE, + (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, + SQL_IS_UINTEGER ); + } else { + r = SQLSetStmtAttr( d->hStmt, + SQL_ATTR_CURSOR_TYPE, + (SQLPOINTER)SQL_CURSOR_STATIC, + SQL_IS_UINTEGER ); + } + if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCResult::reset: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration", d ); +#endif + return FALSE; + } + +#ifdef UNICODE + r = SQLExecDirect( d->hStmt, + (SQLWCHAR*) query.unicode(), + (SQLINTEGER) query.length() ); +#else + QCString query8 = query.local8Bit(); + r = SQLExecDirect( d->hStmt, + (SQLCHAR*) query8.data(), + (SQLINTEGER) query8.length() ); +#endif + if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) { + setLastError( qMakeError( "Unable to execute statement", QSqlError::Statement, d ) ); + return FALSE; + } + SQLSMALLINT count; + r = SQLNumResultCols( d->hStmt, &count ); + if ( count ) { + setSelect( TRUE ); + for ( int i = 0; i < count; ++i ) { + d->rInf.append( qMakeFieldInfo( d, i ) ); + } + } else { + setSelect( FALSE ); + } + setActive( TRUE ); + return TRUE; +} + +bool QODBCResult::fetch(int i) +{ + if ( isForwardOnly() && i < at() ) + return FALSE; + if ( i == at() ) + return TRUE; + fieldCache.clear(); + nullCache.clear(); + int actualIdx = i + 1; + if ( actualIdx <= 0 ) { + setAt( QSql::BeforeFirst ); + return FALSE; + } + SQLRETURN r; + if ( isForwardOnly() ) { + bool ok = TRUE; + while ( ok && i > at() ) + ok = fetchNext(); + return ok; + } else { + r = SQLFetchScroll( d->hStmt, + SQL_FETCH_ABSOLUTE, + actualIdx ); + } + if ( r != SQL_SUCCESS ){ + return FALSE; + } + setAt( i ); + return TRUE; +} + +bool QODBCResult::fetchNext() +{ + SQLRETURN r; + fieldCache.clear(); + nullCache.clear(); + r = SQLFetchScroll( d->hStmt, + SQL_FETCH_NEXT, + 0 ); + if ( r != SQL_SUCCESS ) + return FALSE; + setAt( at() + 1 ); + return TRUE; +} + +bool QODBCResult::fetchFirst() +{ + if ( isForwardOnly() && at() != QSql::BeforeFirst ) + return FALSE; + SQLRETURN r; + fieldCache.clear(); + nullCache.clear(); + if ( isForwardOnly() ) { + return fetchNext(); + } + r = SQLFetchScroll( d->hStmt, + SQL_FETCH_FIRST, + 0 ); + if ( r != SQL_SUCCESS ) + return FALSE; + setAt( 0 ); + return TRUE; +} + +bool QODBCResult::fetchPrior() +{ + if ( isForwardOnly() ) + return FALSE; + SQLRETURN r; + fieldCache.clear(); + nullCache.clear(); + r = SQLFetchScroll( d->hStmt, + SQL_FETCH_PRIOR, + 0 ); + if ( r != SQL_SUCCESS ) + return FALSE; + setAt( at() - 1 ); + return TRUE; +} + +bool QODBCResult::fetchLast() +{ + SQLRETURN r; + fieldCache.clear(); + nullCache.clear(); + + if ( isForwardOnly() ) { + // cannot seek to last row in forwardOnly mode, so we have to use brute force + int i = at(); + if ( i == QSql::AfterLast ) + return FALSE; + if ( i == QSql::BeforeFirst ) + i = 0; + while ( fetchNext() ) + ++i; + setAt( i ); + return TRUE; + } + + r = SQLFetchScroll( d->hStmt, + SQL_FETCH_LAST, + 0 ); + if ( r != SQL_SUCCESS ) { + return FALSE; + } + SQLINTEGER currRow; + r = SQLGetStmtAttr( d->hStmt, + SQL_ROW_NUMBER, + &currRow, + SQL_IS_INTEGER, + 0 ); + if ( r != SQL_SUCCESS ) + return FALSE; + setAt( currRow-1 ); + return TRUE; +} + +QVariant QODBCResult::data( int field ) +{ + if ( field >= (int) d->rInf.count() ) { + qWarning( "QODBCResult::data: column %d out of range", field ); + return QVariant(); + } + if ( fieldCache.contains( field ) ) + return fieldCache[ field ]; + SQLRETURN r(0); + QSQLLEN lengthIndicator = 0; + bool isNull = FALSE; + int current = fieldCache.count(); + for ( ; current < (field + 1); ++current ) { + const QSqlFieldInfo info = d->rInf[ current ]; + switch ( info.type() ) { + case QVariant::LongLong: + fieldCache[ current ] = QVariant( (Q_LLONG) qGetBigIntData( d->hStmt, current, isNull ) ); + nullCache[ current ] = isNull; + break; + case QVariant::Int: + fieldCache[ current ] = QVariant( qGetIntData( d->hStmt, current, isNull ) ); + nullCache[ current ] = isNull; + break; + case QVariant::Date: + DATE_STRUCT dbuf; + r = SQLGetData( d->hStmt, + current+1, + SQL_C_DATE, + (SQLPOINTER)&dbuf, + (QSQLLEN)0, + &lengthIndicator ); + if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != SQL_NULL_DATA ) ) { + fieldCache[ current ] = QVariant( QDate( dbuf.year, dbuf.month, dbuf.day ) ); + nullCache[ current ] = FALSE; + } else { + fieldCache[ current ] = QVariant( QDate() ); + nullCache[ current ] = TRUE; + } + break; + case QVariant::Time: + TIME_STRUCT tbuf; + r = SQLGetData( d->hStmt, + current+1, + SQL_C_TIME, + (SQLPOINTER)&tbuf, + (QSQLLEN)0, + &lengthIndicator ); + if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != SQL_NULL_DATA ) ) { + fieldCache[ current ] = QVariant( QTime( tbuf.hour, tbuf.minute, tbuf.second ) ); + nullCache[ current ] = FALSE; + } else { + fieldCache[ current ] = QVariant( QTime() ); + nullCache[ current ] = TRUE; + } + break; + case QVariant::DateTime: + TIMESTAMP_STRUCT dtbuf; + r = SQLGetData( d->hStmt, + current+1, + SQL_C_TIMESTAMP, + (SQLPOINTER)&dtbuf, + (QSQLLEN)0, + &lengthIndicator ); + if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != SQL_NULL_DATA ) ) { + fieldCache[ current ] = QVariant( QDateTime( QDate( dtbuf.year, dtbuf.month, dtbuf.day ), QTime( dtbuf.hour, dtbuf.minute, dtbuf.second, dtbuf.fraction / 1000000 ) ) ); + nullCache[ current ] = FALSE; + } else { + fieldCache[ current ] = QVariant( QDateTime() ); + nullCache[ current ] = TRUE; + } + break; + case QVariant::ByteArray: { + isNull = FALSE; + QByteArray val = qGetBinaryData( d->hStmt, current, lengthIndicator, isNull ); + fieldCache[ current ] = QVariant( val ); + nullCache[ current ] = isNull; + break; } + case QVariant::String: + isNull = FALSE; + fieldCache[ current ] = QVariant( qGetStringData( d->hStmt, current, + info.length(), isNull, TRUE ) ); + nullCache[ current ] = isNull; + break; + case QVariant::Double: + if ( info.typeID() == SQL_DECIMAL || info.typeID() == SQL_NUMERIC ) + // bind Double values as string to prevent loss of precision + fieldCache[ current ] = QVariant( qGetStringData( d->hStmt, current, + info.length() + 1, isNull, FALSE ) ); // length + 1 for the comma + else + fieldCache[ current ] = QVariant( qGetDoubleData( d->hStmt, current, isNull ) ); + nullCache[ current ] = isNull; + break; + case QVariant::CString: + default: + isNull = FALSE; + fieldCache[ current ] = QVariant( qGetStringData( d->hStmt, current, + info.length(), isNull, FALSE ) ); + nullCache[ current ] = isNull; + break; + } + } + return fieldCache[ --current ]; +} + +bool QODBCResult::isNull( int field ) +{ + if ( !fieldCache.contains( field ) ) { + // since there is no good way to find out whether the value is NULL + // without fetching the field we'll fetch it here. + // (data() also sets the NULL flag) + data( field ); + } + return nullCache[ field ]; +} + +int QODBCResult::size() +{ + return -1; +} + +int QODBCResult::numRowsAffected() +{ + QSQLLEN affectedRowCount(0); + SQLRETURN r = SQLRowCount( d->hStmt, &affectedRowCount ); + if ( r == SQL_SUCCESS ) + return affectedRowCount; +#ifdef QT_CHECK_RANGE + else + qSqlWarning( "QODBCResult::numRowsAffected: Unable to count affected rows", d ); +#endif + return -1; +} + +bool QODBCResult::prepare( const QString& query ) +{ + setActive( FALSE ); + setAt( QSql::BeforeFirst ); + SQLRETURN r; + + d->rInf.clear(); + if ( d->hStmt ) { + r = SQLFreeHandle( SQL_HANDLE_STMT, d->hStmt ); + if ( r != SQL_SUCCESS ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCResult::prepare: Unable to close statement", d ); +#endif + return FALSE; + } + } + r = SQLAllocHandle( SQL_HANDLE_STMT, + d->hDbc, + &d->hStmt ); + if ( r != SQL_SUCCESS ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCResult::prepare: Unable to allocate statement handle", d ); +#endif + return FALSE; + } + + if ( isForwardOnly() ) { + r = SQLSetStmtAttr( d->hStmt, + SQL_ATTR_CURSOR_TYPE, + (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, + SQL_IS_UINTEGER ); + } else { + r = SQLSetStmtAttr( d->hStmt, + SQL_ATTR_CURSOR_TYPE, + (SQLPOINTER)SQL_CURSOR_STATIC, + SQL_IS_UINTEGER ); + } + if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCResult::prepare: Unable to set 'SQL_CURSOR_STATIC' as statement attribute. Please check your ODBC driver configuration", d ); +#endif + return FALSE; + } + +#ifdef UNICODE + r = SQLPrepare( d->hStmt, + (SQLWCHAR*) query.unicode(), + (SQLINTEGER) query.length() ); +#else + QCString query8 = query.local8Bit(); + r = SQLPrepare( d->hStmt, + (SQLCHAR*) query8.data(), + (SQLINTEGER) query8.length() ); +#endif + + if ( r != SQL_SUCCESS ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCResult::prepare: Unable to prepare statement", d ); +#endif + return FALSE; + } + return TRUE; +} + +bool QODBCResult::exec() +{ + SQLRETURN r; + QPtrList<QVirtualDestructor> tmpStorage; // holds temporary ptrs. which will be deleted on fu exit + tmpStorage.setAutoDelete( TRUE ); + + setActive( FALSE ); + setAt( QSql::BeforeFirst ); + d->rInf.clear(); + + if ( !d->hStmt ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCResult::exec: No statement handle available", d ); +#endif + return FALSE; + } else { + r = SQLFreeStmt( d->hStmt, SQL_CLOSE ); + if ( r != SQL_SUCCESS ) { + qSqlWarning( "QODBCResult::exec: Unable to close statement handle", d ); + return FALSE; + } + } + + // bind parameters - only positional binding allowed + if ( extension()->index.count() > 0 ) { + QMap<int, QString>::Iterator it; + int para = 1; + QVariant val; + for ( it = extension()->index.begin(); it != extension()->index.end(); ++it ) { + val = extension()->values[ it.data() ].value; + QSQLLEN *ind = new QSQLLEN( SQL_NTS ); + tmpStorage.append( qAutoDeleter(ind) ); + if ( val.isNull() ) { + *ind = SQL_NULL_DATA; + } + switch ( val.type() ) { + case QVariant::Date: { + DATE_STRUCT * dt = new DATE_STRUCT; + tmpStorage.append( qAutoDeleter(dt) ); + QDate qdt = val.toDate(); + dt->year = qdt.year(); + dt->month = qdt.month(); + dt->day = qdt.day(); + r = SQLBindParameter( d->hStmt, + para, + qParamType[ (int)extension()->values[ it.data() ].typ ], + SQL_C_DATE, + SQL_DATE, + 0, + 0, + (void *) dt, + (QSQLLEN)0, + *ind == SQL_NULL_DATA ? ind : NULL ); + break; } + case QVariant::Time: { + TIME_STRUCT * dt = new TIME_STRUCT; + tmpStorage.append( qAutoDeleter(dt) ); + QTime qdt = val.toTime(); + dt->hour = qdt.hour(); + dt->minute = qdt.minute(); + dt->second = qdt.second(); + r = SQLBindParameter( d->hStmt, + para, + qParamType[ (int)extension()->values[ it.data() ].typ ], + SQL_C_TIME, + SQL_TIME, + 0, + 0, + (void *) dt, + (QSQLLEN)0, + *ind == SQL_NULL_DATA ? ind : NULL ); + break; } + case QVariant::DateTime: { + TIMESTAMP_STRUCT * dt = new TIMESTAMP_STRUCT; + tmpStorage.append( qAutoDeleter(dt) ); + QDateTime qdt = val.toDateTime(); + dt->year = qdt.date().year(); + dt->month = qdt.date().month(); + dt->day = qdt.date().day(); + dt->hour = qdt.time().hour(); + dt->minute = qdt.time().minute(); + dt->second = qdt.time().second(); + dt->fraction = 0; + r = SQLBindParameter( d->hStmt, + para, + qParamType[ (int)extension()->values[ it.data() ].typ ], + SQL_C_TIMESTAMP, + SQL_TIMESTAMP, + 0, + 0, + (void *) dt, + (QSQLLEN)0, + *ind == SQL_NULL_DATA ? ind : NULL ); + break; } + case QVariant::Int: { + int * v = new int( val.toInt() ); + tmpStorage.append( qAutoDeleter(v) ); + r = SQLBindParameter( d->hStmt, + para, + qParamType[ (int)extension()->values[ it.data() ].typ ], + SQL_C_SLONG, + SQL_INTEGER, + 0, + 0, + (void *) v, + (QSQLLEN)0, + *ind == SQL_NULL_DATA ? ind : NULL ); + break; } + case QVariant::Double: { + double * v = new double( val.toDouble() ); + tmpStorage.append( qAutoDeleter(v) ); + r = SQLBindParameter( d->hStmt, + para, + qParamType[ (int)extension()->values[ it.data() ].typ ], + SQL_C_DOUBLE, + SQL_DOUBLE, + 0, + 0, + (void *) v, + (QSQLLEN)0, + *ind == SQL_NULL_DATA ? ind : NULL ); + break; } + case QVariant::ByteArray: { + if ( *ind != SQL_NULL_DATA ) { + *ind = val.asByteArray().size(); + } + r = SQLBindParameter( d->hStmt, + para, + qParamType[ (int)extension()->values[ it.data() ].typ ], + SQL_C_BINARY, + SQL_LONGVARBINARY, + val.asByteArray().size(), + 0, + (void *) val.asByteArray().data(), + (QSQLLEN)val.asByteArray().size(), + ind ); + break; } +#ifndef Q_ODBC_VERSION_2 + case QVariant::String: + if ( d->unicode ) { + QString * str = new QString( val.asString() ); + str->ucs2(); + int len = str->length()*2; + tmpStorage.append( qAutoDeleter(str) ); + r = SQLBindParameter( d->hStmt, + para, + qParamType[ (int)extension()->values[ it.data() ].typ ], + SQL_C_WCHAR, + len > 8000 ? SQL_WLONGVARCHAR : SQL_WVARCHAR, + len > 8000 ? len : 0, + 0, + (void *) str->unicode(), + (QSQLLEN) len, + ind ); + break; + } +#endif + // fall through + default: { + QCString * str = new QCString( val.asString().local8Bit() ); + tmpStorage.append( qAutoDeleter(str) ); + r = SQLBindParameter( d->hStmt, + para, + qParamType[ (int)extension()->values[ it.data() ].typ ], + SQL_C_CHAR, + str->length() > 4000 ? SQL_LONGVARCHAR : SQL_VARCHAR, + str->length() + 1, + 0, + (void *) str->data(), + (QSQLLEN)(str->length() + 1), + ind ); + break; } + } + para++; + if ( r != SQL_SUCCESS ) { +#ifdef QT_CHECK_RANGE + qWarning( "QODBCResult::exec: unable to bind variable: %s", qODBCWarn( d ).local8Bit().data() ); +#endif + setLastError( qMakeError( "Unable to bind variable", QSqlError::Statement, d ) ); + return FALSE; + } + } + } + r = SQLExecute( d->hStmt ); + if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) { +#ifdef QT_CHECK_RANGE + qWarning( "QODBCResult::exec: Unable to execute statement: %s", qODBCWarn( d ).local8Bit().data() ); +#endif + setLastError( qMakeError( "Unable to execute statement", QSqlError::Statement, d ) ); + return FALSE; + } + SQLSMALLINT count; + r = SQLNumResultCols( d->hStmt, &count ); + if ( count ) { + setSelect( TRUE ); + for ( int i = 0; i < count; ++i ) { + d->rInf.append( qMakeFieldInfo( d, i ) ); + } + } else { + setSelect( FALSE ); + } + setActive( TRUE ); + + //get out parameters + if ( extension()->index.count() > 0 ) { + QMap<int, QString>::Iterator it; + for ( it = extension()->index.begin(); it != extension()->index.end(); ++it ) { + + SQLINTEGER* indPtr = qAutoDeleterData( (QAutoDeleter<SQLINTEGER>*)tmpStorage.getFirst() ); + if ( !indPtr ) + return FALSE; + bool isNull = (*indPtr == SQL_NULL_DATA); + tmpStorage.removeFirst(); + + QVariant::Type type = extension()->values[ it.data() ].value.type(); + if ( isNull ) { + QVariant v; + v.cast(type); + extension()->values[ it.data() ].value = v; + if (type != QVariant::ByteArray) + tmpStorage.removeFirst(); + continue; + } + + switch (type) { + case QVariant::Date: { + DATE_STRUCT * ds = qAutoDeleterData( (QAutoDeleter<DATE_STRUCT>*)tmpStorage.getFirst() ); + extension()->values[ it.data() ].value = QVariant( QDate( ds->year, ds->month, ds->day ) ); + break; } + case QVariant::Time: { + TIME_STRUCT * dt = qAutoDeleterData( (QAutoDeleter<TIME_STRUCT>*)tmpStorage.getFirst() ); + extension()->values[ it.data() ].value = QVariant( QTime( dt->hour, dt->minute, dt->second ) ); + break; } + case QVariant::DateTime: { + TIMESTAMP_STRUCT * dt = qAutoDeleterData( (QAutoDeleter<TIMESTAMP_STRUCT>*)tmpStorage.getFirst() ); + extension()->values[ it.data() ].value = QVariant( QDateTime( QDate( dt->year, dt->month, dt->day ), + QTime( dt->hour, dt->minute, dt->second ) ) ); + break; } + case QVariant::Int: { + int * v = qAutoDeleterData( (QAutoDeleter<int>*)tmpStorage.getFirst() ); + extension()->values[ it.data() ].value = QVariant( *v ); + break; } + case QVariant::Double: { + double * v = qAutoDeleterData( (QAutoDeleter<double>*)tmpStorage.getFirst() ); + extension()->values[ it.data() ].value = QVariant( *v ); + break; } + case QVariant::ByteArray: + break; + case QVariant::String: + if ( d->unicode ) { + QString * str = qAutoDeleterData( (QAutoDeleter<QString>*)tmpStorage.getFirst() ); + extension()->values[ it.data() ].value = QVariant( *str ); + break; + } + // fall through + default: { + QCString * str = qAutoDeleterData( (QAutoDeleter<QCString>*)tmpStorage.getFirst() ); + extension()->values[ it.data() ].value = QVariant( *str ); + break; } + } + if (type != QVariant::ByteArray) + tmpStorage.removeFirst(); + } + } + + return TRUE; +} + +//////////////////////////////////////// + + +QODBCDriver::QODBCDriver( QObject * parent, const char * name ) + : QSqlDriver(parent,name ? name : "QODBC") +{ + init(); +} + +QODBCDriver::QODBCDriver( SQLHANDLE env, SQLHANDLE con, QObject * parent, const char * name ) + : QSqlDriver(parent,name ? name : "QODBC") +{ + init(); + d->hEnv = env; + d->hDbc = con; + if ( env && con ) { + setOpen( TRUE ); + setOpenError( FALSE ); + } +} + +void QODBCDriver::init() +{ + qSqlOpenExtDict()->insert( this, new QODBCOpenExtension(this) ); + d = new QODBCPrivate(); +} + +QODBCDriver::~QODBCDriver() +{ + cleanup(); + delete d; + if ( !qSqlOpenExtDict()->isEmpty() ) { + QSqlOpenExtension *ext = qSqlOpenExtDict()->take( this ); + delete ext; + } +} + +bool QODBCDriver::hasFeature( DriverFeature f ) const +{ + switch ( f ) { + case Transactions: { + if ( !d->hDbc ) + return FALSE; + SQLUSMALLINT txn; + SQLSMALLINT t; + int r = SQLGetInfo( d->hDbc, + (SQLUSMALLINT)SQL_TXN_CAPABLE, + &txn, + sizeof(txn), + &t); + if ( r != SQL_SUCCESS || txn == SQL_TC_NONE ) + return FALSE; + else + return TRUE; + } + case QuerySize: + return FALSE; + case BLOB: + return TRUE; + case Unicode: + return d->unicode; + case PreparedQueries: + return TRUE; + case PositionalPlaceholders: + return TRUE; + default: + return FALSE; + } +} + +bool QODBCDriver::open( const QString&, + const QString&, + const QString&, + const QString&, + int ) +{ + qWarning("QODBCDriver::open(): This version of open() is no longer supported." ); + return FALSE; +} + +bool QODBCDriver::open( const QString & db, + const QString & user, + const QString & password, + const QString &, + int, + const QString& connOpts ) +{ + if ( isOpen() ) + close(); + SQLRETURN r; + r = SQLAllocHandle( SQL_HANDLE_ENV, + SQL_NULL_HANDLE, + &d->hEnv); + if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCDriver::open: Unable to allocate environment", d ); +#endif + setOpenError( TRUE ); + return FALSE; + } + r = SQLSetEnvAttr( d->hEnv, + SQL_ATTR_ODBC_VERSION, + (SQLPOINTER)SQL_OV_ODBC2, + SQL_IS_UINTEGER ); + r = SQLAllocHandle( SQL_HANDLE_DBC, + d->hEnv, + &d->hDbc); + if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCDriver::open: Unable to allocate connection", d ); +#endif + setOpenError( TRUE ); + return FALSE; + } + + if ( !d->setConnectionOptions( connOpts ) ) + return FALSE; + + // Create the connection string + QString connQStr; + // support the "DRIVER={SQL SERVER};SERVER=blah" syntax + if ( db.contains(".dsn") ) + connQStr = "FILEDSN=" + db; + else if ( db.contains( "DRIVER" ) || db.contains( "SERVER" ) ) + connQStr = db; + else + connQStr = "DSN=" + db; + connQStr += ";UID=" + user + ";PWD=" + password; + SQLSMALLINT cb; + SQLTCHAR connOut[1024]; + r = SQLDriverConnect( d->hDbc, + NULL, +#ifdef UNICODE + (SQLWCHAR*)connQStr.unicode(), +#else + (SQLCHAR*)connQStr.latin1(), +#endif + (SQLSMALLINT)connQStr.length(), + connOut, + 1024, + &cb, + SQL_DRIVER_NOPROMPT ); + if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) { + setLastError( qMakeError( "Unable to connect", QSqlError::Connection, d ) ); + setOpenError( TRUE ); + return FALSE; + } + + if ( !d->checkDriver() ) { + setLastError( qMakeError( "Unable to connect - Driver doesn't support all needed functionality", QSqlError::Connection, d ) ); + setOpenError( TRUE ); + return FALSE; + } + + d->checkUnicode(); + d->checkSchemaUsage(); + + setOpen( TRUE ); + setOpenError( FALSE ); + return TRUE; +} + +void QODBCDriver::close() +{ + cleanup(); + setOpen( FALSE ); + setOpenError( FALSE ); +} + +void QODBCDriver::cleanup() +{ + SQLRETURN r; + if ( !d ) + return; + + if( d->hDbc ) { + // Open statements/descriptors handles are automatically cleaned up by SQLDisconnect + if ( isOpen() ) { + r = SQLDisconnect( d->hDbc ); +#ifdef QT_CHECK_RANGE + if ( r != SQL_SUCCESS ) + qSqlWarning( "QODBCDriver::disconnect: Unable to disconnect datasource", d ); +#endif + } + + r = SQLFreeHandle( SQL_HANDLE_DBC, d->hDbc ); +#ifdef QT_CHECK_RANGE + if ( r != SQL_SUCCESS ) + qSqlWarning( "QODBCDriver::cleanup: Unable to free connection handle", d ); +#endif + d->hDbc = 0; + } + + if ( d->hEnv ) { + r = SQLFreeHandle( SQL_HANDLE_ENV, d->hEnv ); +#ifdef QT_CHECK_RANGE + if ( r != SQL_SUCCESS ) + qSqlWarning( "QODBCDriver::cleanup: Unable to free environment handle", d ); +#endif + d->hEnv = 0; + } +} + +// checks whether the server can return char, varchar and longvarchar +// as two byte unicode characters +void QODBCPrivate::checkUnicode() +{ +#if defined(Q_WS_WIN) + if ( !qt_winunicode ) { + unicode = FALSE; + return; + } +#endif + SQLRETURN r; + SQLUINTEGER fFunc; + + unicode = FALSE; + r = SQLGetInfo( hDbc, + SQL_CONVERT_CHAR, + (SQLPOINTER)&fFunc, + sizeof(fFunc), + NULL ); + if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( fFunc & SQL_CVT_WCHAR ) ) { + sql_char_type = QVariant::String; + unicode = TRUE; + } + + r = SQLGetInfo( hDbc, + SQL_CONVERT_VARCHAR, + (SQLPOINTER)&fFunc, + sizeof(fFunc), + NULL ); + if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( fFunc & SQL_CVT_WVARCHAR ) ) { + sql_varchar_type = QVariant::String; + unicode = TRUE; + } + + r = SQLGetInfo( hDbc, + SQL_CONVERT_LONGVARCHAR, + (SQLPOINTER)&fFunc, + sizeof(fFunc), + NULL ); + if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( fFunc & SQL_CVT_WLONGVARCHAR ) ) { + sql_longvarchar_type = QVariant::String; + unicode = TRUE; + } +} + +bool QODBCPrivate::checkDriver() const +{ +#ifdef ODBC_CHECK_DRIVER + // do not query for SQL_API_SQLFETCHSCROLL because it can't be used at this time + static const SQLUSMALLINT reqFunc[] = { + SQL_API_SQLDESCRIBECOL, SQL_API_SQLGETDATA, SQL_API_SQLCOLUMNS, + SQL_API_SQLGETSTMTATTR, SQL_API_SQLGETDIAGREC, SQL_API_SQLEXECDIRECT, + SQL_API_SQLGETINFO, SQL_API_SQLTABLES, 0 + }; + + // these functions are optional + static const SQLUSMALLINT optFunc[] = { + SQL_API_SQLNUMRESULTCOLS, SQL_API_SQLROWCOUNT, 0 + }; + + SQLRETURN r; + SQLUSMALLINT sup; + + + int i; + // check the required functions + for ( i = 0; reqFunc[ i ] != 0; ++i ) { + + r = SQLGetFunctions( hDbc, reqFunc[ i ], &sup ); + +#ifdef QT_CHECK_RANGE + if ( r != SQL_SUCCESS ) { + qSqlWarning( "QODBCDriver::checkDriver: Cannot get list of supported functions", this ); + return FALSE; + } +#endif + if ( sup == SQL_FALSE ) { +#ifdef QT_CHECK_RANGE + qWarning ( "QODBCDriver::open: Warning - Driver doesn't support all needed functionality (%d). " + "Please look at the Qt SQL Module Driver documentation for more information.", reqFunc[ i ] ); +#endif + return FALSE; + } + } + + // these functions are optional and just generate a warning + for ( i = 0; optFunc[ i ] != 0; ++i ) { + + r = SQLGetFunctions( hDbc, optFunc[ i ], &sup ); + +#ifdef QT_CHECK_RANGE + if ( r != SQL_SUCCESS ) { + qSqlWarning( "QODBCDriver::checkDriver: Cannot get list of supported functions", this ); + return FALSE; + } +#endif + if ( sup == SQL_FALSE ) { +#ifdef QT_CHECK_RANGE + qWarning( "QODBCDriver::checkDriver: Warning - Driver doesn't support some non-critical functions (%d)", optFunc[ i ] ); +#endif + return TRUE; + } + } +#endif //ODBC_CHECK_DRIVER + + return TRUE; +} + +void QODBCPrivate::checkSchemaUsage() +{ + SQLRETURN r; + SQLUINTEGER val; + + r = SQLGetInfo(hDbc, + SQL_SCHEMA_USAGE, + (SQLPOINTER) &val, + sizeof(val), + NULL); + if (r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO) + useSchema = (val != 0); +} + +QSqlQuery QODBCDriver::createQuery() const +{ + return QSqlQuery( new QODBCResult( this, d ) ); +} + +bool QODBCDriver::beginTransaction() +{ + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + qWarning(" QODBCDriver::beginTransaction: Database not open" ); +#endif + return FALSE; + } + SQLUINTEGER ac(SQL_AUTOCOMMIT_OFF); + SQLRETURN r = SQLSetConnectAttr( d->hDbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)ac, + sizeof(ac) ); + if ( r != SQL_SUCCESS ) { + setLastError( qMakeError( "Unable to disable autocommit", QSqlError::Transaction, d ) ); + return FALSE; + } + return TRUE; +} + +bool QODBCDriver::commitTransaction() +{ + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + qWarning(" QODBCDriver::commitTransaction: Database not open" ); +#endif + return FALSE; + } + SQLRETURN r = SQLEndTran( SQL_HANDLE_DBC, + d->hDbc, + SQL_COMMIT ); + if ( r != SQL_SUCCESS ) { + setLastError( qMakeError("Unable to commit transaction", QSqlError::Transaction, d ) ); + return FALSE; + } + return endTrans(); +} + +bool QODBCDriver::rollbackTransaction() +{ + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + qWarning(" QODBCDriver::rollbackTransaction: Database not open" ); +#endif + return FALSE; + } + SQLRETURN r = SQLEndTran( SQL_HANDLE_DBC, + d->hDbc, + SQL_ROLLBACK ); + if ( r != SQL_SUCCESS ) { + setLastError( qMakeError( "Unable to rollback transaction", QSqlError::Transaction, d ) ); + return FALSE; + } + return endTrans(); +} + +bool QODBCDriver::endTrans() +{ + SQLUINTEGER ac(SQL_AUTOCOMMIT_ON); + SQLRETURN r = SQLSetConnectAttr( d->hDbc, + SQL_ATTR_AUTOCOMMIT, + (SQLPOINTER)ac, + sizeof(ac)); + if ( r != SQL_SUCCESS ) { + setLastError( qMakeError( "Unable to enable autocommit", QSqlError::Transaction, d ) ); + return FALSE; + } + return TRUE; +} + +QStringList QODBCDriver::tables( const QString& typeName ) const +{ + QStringList tl; + if ( !isOpen() ) + return tl; + int type = typeName.toInt(); + SQLHANDLE hStmt; + + SQLRETURN r = SQLAllocHandle( SQL_HANDLE_STMT, + d->hDbc, + &hStmt ); + if ( r != SQL_SUCCESS ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCDriver::tables: Unable to allocate handle", d ); +#endif + return tl; + } + r = SQLSetStmtAttr( hStmt, + SQL_ATTR_CURSOR_TYPE, + (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, + SQL_IS_UINTEGER ); + QString tableType; + if ( typeName.isEmpty() || ((type & (int)QSql::Tables) == (int)QSql::Tables) ) + tableType += "TABLE,"; + if ( (type & (int)QSql::Views) == (int)QSql::Views ) + tableType += "VIEW,"; + if ( (type & (int)QSql::SystemTables) == (int)QSql::SystemTables ) + tableType += "SYSTEM TABLE,"; + if ( tableType.isEmpty() ) + return tl; + tableType.truncate( tableType.length() - 1 ); + + r = SQLTables( hStmt, + NULL, + 0, + NULL, + 0, + NULL, + 0, +#ifdef UNICODE + (SQLWCHAR*)tableType.unicode(), +#else + (SQLCHAR*)tableType.latin1(), +#endif + tableType.length() /* characters, not bytes */ ); + +#ifdef QT_CHECK_RANGE + if ( r != SQL_SUCCESS ) + qSqlWarning( "QODBCDriver::tables Unable to execute table list", d ); +#endif + r = SQLFetchScroll( hStmt, + SQL_FETCH_NEXT, + 0); + while ( r == SQL_SUCCESS ) { + bool isNull; + QString fieldVal = qGetStringData( hStmt, 2, -1, isNull, d->unicode ); + tl.append( fieldVal ); + r = SQLFetchScroll( hStmt, + SQL_FETCH_NEXT, + 0); + } + + r = SQLFreeHandle( SQL_HANDLE_STMT, hStmt ); + if ( r!= SQL_SUCCESS ) + qSqlWarning( "QODBCDriver: Unable to free statement handle" + QString::number(r), d ); + return tl; +} + +QSqlIndex QODBCDriver::primaryIndex( const QString& tablename ) const +{ + QSqlIndex index( tablename ); + if ( !isOpen() ) + return index; + bool usingSpecialColumns = FALSE; + QSqlRecord rec = record( tablename ); + + SQLHANDLE hStmt; + SQLRETURN r = SQLAllocHandle( SQL_HANDLE_STMT, + d->hDbc, + &hStmt ); + if ( r != SQL_SUCCESS ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCDriver::primaryIndex: Unable to list primary key", d ); +#endif + return index; + } + QString catalog, schema, table; + d->splitTableQualifier( tablename, catalog, schema, table ); + r = SQLSetStmtAttr( hStmt, + SQL_ATTR_CURSOR_TYPE, + (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, + SQL_IS_UINTEGER ); + r = SQLPrimaryKeys( hStmt, +#ifdef UNICODE + catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(), +#else + catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.latin1(), +#endif + catalog.length(), +#ifdef UNICODE + schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(), +#else + schema.length() == 0 ? NULL : (SQLCHAR*)schema.latin1(), +#endif + schema.length(), +#ifdef UNICODE + (SQLWCHAR*)table.unicode(), +#else + (SQLCHAR*)table.latin1(), +#endif + table.length() /* in characters, not in bytes */); + + // if the SQLPrimaryKeys() call does not succeed (e.g the driver + // does not support it) - try an alternative method to get hold of + // the primary index (e.g MS Access and FoxPro) + if ( r != SQL_SUCCESS ) { + r = SQLSpecialColumns( hStmt, + SQL_BEST_ROWID, +#ifdef UNICODE + catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(), +#else + catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.latin1(), +#endif + catalog.length(), +#ifdef UNICODE + schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(), +#else + schema.length() == 0 ? NULL : (SQLCHAR*)schema.latin1(), +#endif + schema.length(), +#ifdef UNICODE + (SQLWCHAR*)table.unicode(), +#else + (SQLCHAR*)table.latin1(), +#endif + + table.length(), + SQL_SCOPE_CURROW, + SQL_NULLABLE ); + + if ( r != SQL_SUCCESS ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCDriver::primaryIndex: Unable to execute primary key list", d ); +#endif + } else { + usingSpecialColumns = TRUE; + } + } + r = SQLFetchScroll( hStmt, + SQL_FETCH_NEXT, + 0 ); + bool isNull; + int fakeId = 0; + QString cName, idxName; + // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop + while ( r == SQL_SUCCESS ) { + if ( usingSpecialColumns ) { + cName = qGetStringData( hStmt, 1, -1, isNull, d->unicode ); // column name + idxName = QString::number( fakeId++ ); // invent a fake index name + } else { + cName = qGetStringData( hStmt, 3, -1, isNull, d->unicode ); // column name + idxName = qGetStringData( hStmt, 5, -1, isNull, d->unicode ); // pk index name + } + QSqlField *fld = rec.field(cName); + if (fld) + index.append(*fld); + index.setName( idxName ); + r = SQLFetchScroll( hStmt, + SQL_FETCH_NEXT, + 0 ); + } + r = SQLFreeHandle( SQL_HANDLE_STMT, hStmt ); + if ( r!= SQL_SUCCESS ) + qSqlWarning( "QODBCDriver: Unable to free statement handle" + QString::number(r), d ); + return index; +} + +QSqlRecord QODBCDriver::record( const QString& tablename ) const +{ + return recordInfo( tablename ).toRecord(); +} + +QSqlRecord QODBCDriver::record( const QSqlQuery& query ) const +{ + return recordInfo( query ).toRecord(); +} + +QSqlRecordInfo QODBCDriver::recordInfo( const QString& tablename ) const +{ + QSqlRecordInfo fil; + if ( !isOpen() ) + return fil; + + SQLHANDLE hStmt; + QString catalog, schema, table; + d->splitTableQualifier( tablename, catalog, schema, table ); + SQLRETURN r = SQLAllocHandle( SQL_HANDLE_STMT, + d->hDbc, + &hStmt ); + if ( r != SQL_SUCCESS ) { +#ifdef QT_CHECK_RANGE + qSqlWarning( "QODBCDriver::record: Unable to allocate handle", d ); +#endif + return fil; + } + r = SQLSetStmtAttr( hStmt, + SQL_ATTR_CURSOR_TYPE, + (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY, + SQL_IS_UINTEGER ); + r = SQLColumns( hStmt, +#ifdef UNICODE + catalog.length() == 0 ? NULL : (SQLWCHAR*)catalog.unicode(), +#else + catalog.length() == 0 ? NULL : (SQLCHAR*)catalog.latin1(), +#endif + catalog.length(), +#ifdef UNICODE + schema.length() == 0 ? NULL : (SQLWCHAR*)schema.unicode(), +#else + schema.length() == 0 ? NULL : (SQLCHAR*)schema.latin1(), +#endif + schema.length(), +#ifdef UNICODE + (SQLWCHAR*)table.unicode(), +#else + (SQLCHAR*)table.latin1(), +#endif + table.length(), + NULL, + 0 ); +#ifdef QT_CHECK_RANGE + if ( r != SQL_SUCCESS ) + qSqlWarning( "QODBCDriver::record: Unable to execute column list", d ); +#endif + r = SQLFetchScroll( hStmt, + SQL_FETCH_NEXT, + 0); + // Store all fields in a StringList because some drivers can't detail fields in this FETCH loop + while ( r == SQL_SUCCESS ) { + + fil.append( qMakeFieldInfo( hStmt, d ) ); + + r = SQLFetchScroll( hStmt, + SQL_FETCH_NEXT, + 0); + } + + r = SQLFreeHandle( SQL_HANDLE_STMT, hStmt ); + if ( r!= SQL_SUCCESS ) + qSqlWarning( "QODBCDriver: Unable to free statement handle " + QString::number(r), d ); + + return fil; +} + +QSqlRecordInfo QODBCDriver::recordInfo( const QSqlQuery& query ) const +{ + QSqlRecordInfo fil; + if ( !isOpen() ) + return fil; + if ( query.isActive() && query.driver() == this ) { + QODBCResult* result = (QODBCResult*)query.result(); + fil = result->d->rInf; + } + return fil; +} + +SQLHANDLE QODBCDriver::environment() +{ + return d->hEnv; +} + +SQLHANDLE QODBCDriver::connection() +{ + return d->hDbc; +} + +QString QODBCDriver::formatValue( const QSqlField* field, + bool trimStrings ) const +{ + QString r; + if ( field->isNull() ) { + r = nullText(); + } else if ( field->type() == QVariant::DateTime ) { + // Use an escape sequence for the datetime fields + if ( field->value().toDateTime().isValid() ){ + QDate dt = field->value().toDateTime().date(); + QTime tm = field->value().toDateTime().time(); + // Dateformat has to be "yyyy-MM-dd hh:mm:ss", with leading zeroes if month or day < 10 + r = "{ ts '" + + QString::number(dt.year()) + "-" + + QString::number(dt.month()).rightJustify( 2, '0', TRUE ) + "-" + + QString::number(dt.day()).rightJustify( 2, '0', TRUE ) + " " + + tm.toString() + + "' }"; + } else + r = nullText(); + } else if ( field->type() == QVariant::ByteArray ) { + QByteArray ba = field->value().toByteArray(); + QString res; + static const char hexchars[] = "0123456789abcdef"; + for ( uint i = 0; i < ba.size(); ++i ) { + uchar s = (uchar) ba[(int)i]; + res += hexchars[s >> 4]; + res += hexchars[s & 0x0f]; + } + r = "0x" + res; + } else { + r = QSqlDriver::formatValue( field, trimStrings ); + } + return r; +} diff --git a/main/dependencies/qt3/src/sql/drivers/odbc/qsql_odbc.h b/main/dependencies/qt3/src/sql/drivers/odbc/qsql_odbc.h new file mode 100644 index 000000000..67285c8c5 --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/odbc/qsql_odbc.h @@ -0,0 +1,162 @@ +/**************************************************************************** +** +** Definition of ODBC driver classes +** +** Created : 001103 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQL_ODBC_H +#define QSQL_ODBC_H + +#include <qmap.h> +#include <qstring.h> +#include <qsqldriver.h> +#include <qsqlfield.h> +#include <qsqlresult.h> +#include <qsqlindex.h> + +#if defined (Q_OS_WIN32) +#include <qt_windows.h> +#endif + +#if defined (Q_OS_MAC) +// assume we use iodbc on MAC +// comment next line out if you use a +// unicode compatible manager +# define Q_ODBC_VERSION_2 +#endif + +#ifdef QT_PLUGIN +#define Q_EXPORT_SQLDRIVER_ODBC +#else +#define Q_EXPORT_SQLDRIVER_ODBC Q_EXPORT +#endif + +#ifdef Q_OS_UNIX +#define HAVE_LONG_LONG 1 // force UnixODBC NOT to fall back to a struct for BIGINTs +#endif + +#if defined(Q_CC_BOR) +// workaround for Borland to make sure that SQLBIGINT is defined +# define _MSC_VER 900 +#endif +#include <sql.h> +#if defined(Q_CC_BOR) +# undef _MSC_VER +#endif + +#include <sqlext.h> +#include "debian_qsql_odbc.h" + +class QODBCPrivate; +class QODBCDriver; +class QSqlRecordInfo; + +class QODBCResult : public QSqlResult +{ + friend class QODBCDriver; +public: + QODBCResult( const QODBCDriver * db, QODBCPrivate* p ); + ~QODBCResult(); + + SQLHANDLE statement(); + bool prepare( const QString& query ); + bool exec(); + +protected: + bool fetchNext(); + bool fetchFirst(); + bool fetchLast(); + bool fetchPrior(); + bool fetch(int i); + bool reset ( const QString& query ); + QVariant data( int field ); + bool isNull( int field ); + int size(); + int numRowsAffected(); +private: + QODBCPrivate* d; + typedef QMap<int,QVariant> FieldCache; + FieldCache fieldCache; + typedef QMap<int,bool> NullCache; + NullCache nullCache; +}; + +class Q_EXPORT_SQLDRIVER_ODBC QODBCDriver : public QSqlDriver +{ +public: + QODBCDriver( QObject * parent=0, const char * name=0 ); + QODBCDriver( SQLHANDLE env, SQLHANDLE con, QObject * parent=0, const char * name=0 ); + ~QODBCDriver(); + bool hasFeature( DriverFeature f ) const; + bool open( const QString & db, + const QString & user = QString::null, + const QString & password = QString::null, + const QString & host = QString::null, + int port = -1 ); + void close(); + QSqlQuery createQuery() const; + QStringList tables( const QString& user ) const; + QSqlRecord record( const QString& tablename ) const; + QSqlRecord record( const QSqlQuery& query ) const; + QSqlRecordInfo recordInfo( const QString& tablename ) const; + QSqlRecordInfo recordInfo( const QSqlQuery& query ) const; + QSqlIndex primaryIndex( const QString& tablename ) const; + SQLHANDLE environment(); + SQLHANDLE connection(); + + QString formatValue( const QSqlField* field, + bool trimStrings ) const; + // ### remove me for 4.0 + bool open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ); + +protected: + bool beginTransaction(); + bool commitTransaction(); + bool rollbackTransaction(); +private: + void init(); + bool endTrans(); + void cleanup(); + QODBCPrivate* d; +}; + +#endif diff --git a/main/dependencies/qt3/src/sql/drivers/psql/qsql_psql.cpp b/main/dependencies/qt3/src/sql/drivers/psql/qsql_psql.cpp new file mode 100644 index 000000000..7fe1a915d --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/psql/qsql_psql.cpp @@ -0,0 +1,1117 @@ +/**************************************************************************** +** +** Implementation of PostgreSQL driver classes +** +** Created : 001103 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsql_psql.h" +#include <private/qsqlextension_p.h> + +#include <math.h> + +#include <qpointarray.h> +#include <qsqlrecord.h> +#include <qregexp.h> +#include <qdatetime.h> +// PostgreSQL header <utils/elog.h> included by <postgres.h> redefines DEBUG. +#if defined(DEBUG) +# undef DEBUG +#endif +#include <postgres.h> +#include <libpq/libpq-fs.h> +// PostgreSQL header <catalog/pg_type.h> redefines errno erroneously. +#if defined(errno) +# undef errno +#endif +#define errno qt_psql_errno +#include <catalog/pg_type.h> +#undef errno +#ifdef open +# undef open +#endif + +QPtrDict<QSqlDriverExtension> *qSqlDriverExtDict(); +QPtrDict<QSqlOpenExtension> *qSqlOpenExtDict(); + +class QPSQLPrivate +{ +public: + QPSQLPrivate():connection(0), result(0), isUtf8(FALSE) {} + PGconn *connection; + PGresult *result; + bool isUtf8; +}; + +class QPSQLDriverExtension : public QSqlDriverExtension +{ +public: + QPSQLDriverExtension( QPSQLDriver *dri ) + : QSqlDriverExtension(), driver(dri) { } + ~QPSQLDriverExtension() {} + + bool isOpen() const; +private: + QPSQLDriver *driver; +}; + +bool QPSQLDriverExtension::isOpen() const +{ + return PQstatus( driver->connection() ) == CONNECTION_OK; +} + +class QPSQLOpenExtension : public QSqlOpenExtension +{ +public: + QPSQLOpenExtension( QPSQLDriver *dri ) + : QSqlOpenExtension(), driver(dri) { } + ~QPSQLOpenExtension() {} + + bool open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ); +private: + QPSQLDriver *driver; +}; + +bool QPSQLOpenExtension::open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ) +{ + return driver->open( db, user, password, host, port, connOpts ); +} + +static QSqlError qMakeError( const QString& err, int type, const QPSQLPrivate* p ) +{ + const char *s = PQerrorMessage(p->connection); + QString msg = p->isUtf8 ? QString::fromUtf8(s) : QString::fromLocal8Bit(s); + return QSqlError("QPSQL: " + err, msg, type); +} + +static QVariant::Type qDecodePSQLType( int t ) +{ + QVariant::Type type = QVariant::Invalid; + switch ( t ) { + case BOOLOID : + type = QVariant::Bool; + break; + case INT8OID : + type = QVariant::LongLong; + break; + case INT2OID : + // case INT2VECTOROID : // 7.x + case INT4OID : + type = QVariant::Int; + break; + case NUMERICOID : + case FLOAT4OID : + case FLOAT8OID : + type = QVariant::Double; + break; + case ABSTIMEOID : + case RELTIMEOID : + case DATEOID : + type = QVariant::Date; + break; + case TIMEOID : +#ifdef TIMETZOID // 7.x + case TIMETZOID : +#endif + type = QVariant::Time; + break; + case TIMESTAMPOID : +#ifdef DATETIMEOID + // Postgres 6.x datetime workaround. + // DATETIMEOID == TIMESTAMPOID (only the names have changed) + case DATETIMEOID : +#endif +#ifdef TIMESTAMPTZOID + // Postgres 7.2 workaround + // TIMESTAMPTZOID == TIMESTAMPOID == DATETIMEOID + case TIMESTAMPTZOID : +#endif + type = QVariant::DateTime; + break; + // case ZPBITOID : // 7.x + // case VARBITOID : // 7.x + case OIDOID : + case BYTEAOID : + type = QVariant::ByteArray; + break; + case REGPROCOID : + case TIDOID : + case XIDOID : + case CIDOID : + // case OIDVECTOROID : // 7.x + case UNKNOWNOID : + // case TINTERVALOID : // 7.x + type = QVariant::Invalid; + break; + default: + case CHAROID : + case BPCHAROID : + // case LZTEXTOID : // 7.x + case VARCHAROID : + case TEXTOID : + case NAMEOID : + case CASHOID : + case INETOID : + case CIDROID : + case CIRCLEOID : + type = QVariant::String; + break; + } + return type; +} + +QPSQLResult::QPSQLResult( const QPSQLDriver* db, const QPSQLPrivate* p ) +: QSqlResult( db ), + currentSize( 0 ) +{ + d = new QPSQLPrivate(); + (*d) = (*p); +} + +QPSQLResult::~QPSQLResult() +{ + cleanup(); + delete d; +} + +PGresult* QPSQLResult::result() +{ + return d->result; +} + +void QPSQLResult::cleanup() +{ + if ( d->result ) + PQclear( d->result ); + d->result = 0; + setAt( -1 ); + currentSize = 0; + setActive( FALSE ); +} + +bool QPSQLResult::fetch( int i ) +{ + if ( !isActive() ) + return FALSE; + if ( i < 0 ) + return FALSE; + if ( i >= currentSize ) + return FALSE; + if ( at() == i ) + return TRUE; + setAt( i ); + return TRUE; +} + +bool QPSQLResult::fetchFirst() +{ + return fetch( 0 ); +} + +bool QPSQLResult::fetchLast() +{ + return fetch( PQntuples( d->result ) - 1 ); +} + +// some Postgres conversions +static QPoint pointFromString( const QString& s) +{ + // format '(x,y)' + int pivot = s.find( ',' ); + if ( pivot != -1 ) { + int x = s.mid( 1, pivot-1 ).toInt(); + int y = s.mid( pivot+1, s.length()-pivot-2 ).toInt(); + return QPoint( x, y ) ; + } else + return QPoint(); +} + +QVariant QPSQLResult::data( int i ) +{ + if ( i >= PQnfields( d->result ) ) { + qWarning( "QPSQLResult::data: column %d out of range", i ); + return QVariant(); + } + int ptype = PQftype( d->result, i ); + QVariant::Type type = qDecodePSQLType( ptype ); + const QString val = ( d->isUtf8 && ptype != BYTEAOID ) ? + QString::fromUtf8( PQgetvalue( d->result, at(), i ) ) : + QString::fromLocal8Bit( PQgetvalue( d->result, at(), i ) ); + if ( PQgetisnull( d->result, at(), i ) ) { + QVariant v; + v.cast( type ); + return v; + } + switch ( type ) { + case QVariant::Bool: + { + QVariant b ( (bool)(val == "t"), 0 ); + return ( b ); + } + case QVariant::String: + return QVariant( val ); + case QVariant::LongLong: + if ( val[0] == '-' ) + return QVariant( val.toLongLong() ); + else + return QVariant( val.toULongLong() ); + case QVariant::Int: + return QVariant( val.toInt() ); + case QVariant::Double: + if ( ptype == NUMERICOID ) + return QVariant( val ); + return QVariant( val.toDouble() ); + case QVariant::Date: + if ( val.isEmpty() ) { + return QVariant( QDate() ); + } else { + return QVariant( QDate::fromString( val, Qt::ISODate ) ); + } + case QVariant::Time: + if ( val.isEmpty() ) + return QVariant( QTime() ); + if ( val.at( val.length() - 3 ) == '+' ) + // strip the timezone + return QVariant( QTime::fromString( val.left( val.length() - 3 ), Qt::ISODate ) ); + return QVariant( QTime::fromString( val, Qt::ISODate ) ); + case QVariant::DateTime: { + if ( val.length() < 10 ) + return QVariant( QDateTime() ); + // remove the timezone + QString dtval = val; + if ( dtval.at( dtval.length() - 3 ) == '+' ) + dtval.truncate( dtval.length() - 3 ); + // milliseconds are sometimes returned with 2 digits only + if ( dtval.at( dtval.length() - 3 ).isPunct() ) + dtval += '0'; + if ( dtval.isEmpty() ) + return QVariant( QDateTime() ); + else + return QVariant( QDateTime::fromString( dtval, Qt::ISODate ) ); + } + case QVariant::Point: + return QVariant( pointFromString( val ) ); + case QVariant::Rect: // format '(x,y),(x',y')' + { + int pivot = val.find( "),(" ); + if ( pivot != -1 ) + return QVariant( QRect( pointFromString( val.mid(pivot+2,val.length()) ), pointFromString( val.mid(0,pivot+1) ) ) ); + return QVariant( QRect() ); + } + case QVariant::PointArray: // format '((x,y),(x1,y1),...,(xn,yn))' + { + QRegExp pointPattern("\\([0-9-]*,[0-9-]*\\)"); + int points = val.contains( pointPattern ); + QPointArray parray( points ); + int idx = 1; + for ( int i = 0; i < points; i++ ){ + int start = val.find( pointPattern, idx ); + int end = -1; + if ( start != -1 ) { + end = val.find( ')', start+1 ); + if ( end != -1 ) { + parray.setPoint( i, pointFromString( val.mid(idx, end-idx+1) ) ); + } + else + parray.setPoint( i, QPoint() ); + } else { + parray.setPoint( i, QPoint() ); + break; + } + idx = end+2; + } + return QVariant( parray ); + } + case QVariant::ByteArray: { + if ( ptype == BYTEAOID ) { + uint i = 0; + int index = 0; + uint len = val.length(); + static const QChar backslash( '\\' ); + QByteArray ba( (int)len ); + while ( i < len ) { + if ( val.at( i ) == backslash ) { + if ( val.at( i + 1 ).isDigit() ) { + ba[ index++ ] = (char)(val.mid( i + 1, 3 ).toInt( 0, 8 )); + i += 4; + } else { + ba[ index++ ] = val.at( i + 1 ); + i += 2; + } + } else { + ba[ index++ ] = val.at( i++ ).unicode(); + } + } + ba.resize( index ); + return QVariant( ba ); + } + + QByteArray ba; + ((QSqlDriver*)driver())->beginTransaction(); + Oid oid = val.toInt(); + int fd = lo_open( d->connection, oid, INV_READ ); +#ifdef QT_CHECK_RANGE + if ( fd < 0) { + qWarning( "QPSQLResult::data: unable to open large object for read" ); + ((QSqlDriver*)driver())->commitTransaction(); + return QVariant( ba ); + } +#endif + int size = 0; + int retval = lo_lseek( d->connection, fd, 0L, SEEK_END ); + if ( retval >= 0 ) { + size = lo_tell( d->connection, fd ); + lo_lseek( d->connection, fd, 0L, SEEK_SET ); + } + if ( size == 0 ) { + lo_close( d->connection, fd ); + ((QSqlDriver*)driver())->commitTransaction(); + return QVariant( ba ); + } + char * buf = new char[ size ]; + +#ifdef Q_OS_WIN32 + // ### For some reason lo_read() fails if we try to read more than + // ### 32760 bytes + char * p = buf; + int nread = 0; + + while( size < nread ){ + retval = lo_read( d->connection, fd, p, 32760 ); + nread += retval; + p += retval; + } +#else + retval = lo_read( d->connection, fd, buf, size ); +#endif + + if (retval < 0) { + qWarning( "QPSQLResult::data: unable to read large object" ); + } else { + ba.duplicate( buf, size ); + } + delete [] buf; + lo_close( d->connection, fd ); + ((QSqlDriver*)driver())->commitTransaction(); + return QVariant( ba ); + } + default: + case QVariant::Invalid: +#ifdef QT_CHECK_RANGE + qWarning("QPSQLResult::data: unknown data type"); +#endif + ; + } + return QVariant(); +} + +bool QPSQLResult::isNull( int field ) +{ + PQgetvalue( d->result, at(), field ); + return PQgetisnull( d->result, at(), field ); +} + +bool QPSQLResult::reset ( const QString& query ) +{ + cleanup(); + if ( !driver() ) + return FALSE; + if ( !driver()->isOpen() || driver()->isOpenError() ) + return FALSE; + setActive( FALSE ); + setAt( QSql::BeforeFirst ); + if ( d->result ) + PQclear( d->result ); + if ( d->isUtf8 ) { + d->result = PQexec( d->connection, query.utf8().data() ); + } else { + d->result = PQexec( d->connection, query.local8Bit().data() ); + } + int status = PQresultStatus( d->result ); + if ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) { + if ( status == PGRES_TUPLES_OK ) { + setSelect( TRUE ); + currentSize = PQntuples( d->result ); + } else { + setSelect( FALSE ); + currentSize = -1; + } + setActive( TRUE ); + return TRUE; + } + setLastError( qMakeError( "Unable to create query", QSqlError::Statement, d ) ); + return FALSE; +} + +int QPSQLResult::size() +{ + return currentSize; +} + +int QPSQLResult::numRowsAffected() +{ + return QString( PQcmdTuples( d->result ) ).toInt(); +} + +/////////////////////////////////////////////////////////////////// + +static bool setEncodingUtf8( PGconn* connection ) +{ + PGresult* result = PQexec( connection, "SET CLIENT_ENCODING TO 'UNICODE'" ); + int status = PQresultStatus( result ); + PQclear( result ); + return status == PGRES_COMMAND_OK; +} + +static void setDatestyle( PGconn* connection ) +{ + PGresult* result = PQexec( connection, "SET DATESTYLE TO 'ISO'" ); +#ifdef QT_CHECK_RANGE + int status = PQresultStatus( result ); + if ( status != PGRES_COMMAND_OK ) + qWarning( "%s", PQerrorMessage( connection ) ); +#endif + PQclear( result ); +} + +static QPSQLDriver::Protocol getPSQLVersion( PGconn* connection ) +{ + PGresult* result = PQexec( connection, "select version()" ); + int status = PQresultStatus( result ); + if ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) { + QString val( PQgetvalue( result, 0, 0 ) ); + PQclear( result ); + QRegExp rx( "(\\d+)\\.(\\d+)" ); + rx.setMinimal ( TRUE ); // enforce non-greedy RegExp + if ( rx.search( val ) != -1 ) { + int vMaj = rx.cap( 1 ).toInt(); + int vMin = rx.cap( 2 ).toInt(); + if ( vMaj < 6 ) { +#ifdef QT_CHECK_RANGE + qWarning( "This version of PostgreSQL is not supported and may not work." ); +#endif + return QPSQLDriver::Version6; + } + if ( vMaj == 6 ) { + return QPSQLDriver::Version6; + } else if ( vMaj == 7 ) { + if ( vMin < 1 ) + return QPSQLDriver::Version7; + else if ( vMin < 3 ) + return QPSQLDriver::Version71; + } + return QPSQLDriver::Version73; + } + } else { +#ifdef QT_CHECK_RANGE + qWarning( "This version of PostgreSQL is not supported and may not work." ); +#endif + } + + return QPSQLDriver::Version6; +} + +QPSQLDriver::QPSQLDriver( QObject * parent, const char * name ) + : QSqlDriver(parent,name ? name : "QPSQL"), pro( QPSQLDriver::Version6 ) +{ + init(); +} + +QPSQLDriver::QPSQLDriver( PGconn * conn, QObject * parent, const char * name ) + : QSqlDriver(parent,name ? name : "QPSQL"), pro( QPSQLDriver::Version6 ) +{ + init(); + d->connection = conn; + if ( conn ) { + pro = getPSQLVersion( d->connection ); + setOpen( TRUE ); + setOpenError( FALSE ); + } +} + +void QPSQLDriver::init() +{ + qSqlDriverExtDict()->insert( this, new QPSQLDriverExtension(this) ); + qSqlOpenExtDict()->insert( this, new QPSQLOpenExtension(this) ); + + d = new QPSQLPrivate(); +} + +QPSQLDriver::~QPSQLDriver() +{ + if ( d->connection ) + PQfinish( d->connection ); + delete d; + if ( !qSqlDriverExtDict()->isEmpty() ) { + QSqlDriverExtension *ext = qSqlDriverExtDict()->take( this ); + delete ext; + } + if ( !qSqlOpenExtDict()->isEmpty() ) { + QSqlOpenExtension *ext = qSqlOpenExtDict()->take( this ); + delete ext; + } +} + +PGconn* QPSQLDriver::connection() +{ + return d->connection; +} + + +bool QPSQLDriver::hasFeature( DriverFeature f ) const +{ + switch ( f ) { + case Transactions: + return TRUE; + case QuerySize: + return TRUE; + case BLOB: + return pro >= QPSQLDriver::Version71; + case Unicode: + return d->isUtf8; + default: + return FALSE; + } +} + +bool QPSQLDriver::open( const QString&, + const QString&, + const QString&, + const QString&, + int ) +{ + qWarning("QPSQLDriver::open(): This version of open() is no longer supported." ); + return FALSE; +} + +bool QPSQLDriver::open( const QString & db, + const QString & user, + const QString & password, + const QString & host, + int port, + const QString& connOpts ) +{ + if ( isOpen() ) + close(); + QString connectString; + if ( host.length() ) + connectString.append( "host=" ).append( host ); + if ( db.length() ) + connectString.append( " dbname=" ).append( db ); + if ( user.length() ) + connectString.append( " user=" ).append( user ); + if ( password.length() ) + connectString.append( " password=" ).append( password ); + if ( port > -1 ) + connectString.append( " port=" ).append( QString::number( port ) ); + + // add any connect options - the server will handle error detection + if ( !connOpts.isEmpty() ) + connectString += " " + QStringList::split( ';', connOpts ).join( " " ); + + d->connection = PQconnectdb( connectString.local8Bit().data() ); + if ( PQstatus( d->connection ) == CONNECTION_BAD ) { + setLastError( qMakeError("Unable to connect", QSqlError::Connection, d ) ); + setOpenError( TRUE ); + return FALSE; + } + + pro = getPSQLVersion( d->connection ); + d->isUtf8 = setEncodingUtf8( d->connection ); + setDatestyle( d->connection ); + + setOpen( TRUE ); + setOpenError( FALSE ); + return TRUE; +} + +void QPSQLDriver::close() +{ + if ( isOpen() ) { + if (d->connection) + PQfinish( d->connection ); + d->connection = 0; + setOpen( FALSE ); + setOpenError( FALSE ); + } +} + +QSqlQuery QPSQLDriver::createQuery() const +{ + return QSqlQuery( new QPSQLResult( this, d ) ); +} + +bool QPSQLDriver::beginTransaction() +{ + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + qWarning( "QPSQLDriver::beginTransaction: Database not open" ); +#endif + return FALSE; + } + PGresult* res = PQexec( d->connection, "BEGIN" ); + if ( !res || PQresultStatus( res ) != PGRES_COMMAND_OK ) { + PQclear( res ); + setLastError( qMakeError( "Could not begin transaction", QSqlError::Transaction, d ) ); + return FALSE; + } + PQclear( res ); + return TRUE; +} + +bool QPSQLDriver::commitTransaction() +{ + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + qWarning( "QPSQLDriver::commitTransaction: Database not open" ); +#endif + return FALSE; + } + PGresult* res = PQexec( d->connection, "COMMIT" ); + if ( !res || PQresultStatus( res ) != PGRES_COMMAND_OK ) { + PQclear( res ); + setLastError( qMakeError( "Could not commit transaction", QSqlError::Transaction, d ) ); + return FALSE; + } + PQclear( res ); + return TRUE; +} + +bool QPSQLDriver::rollbackTransaction() +{ + if ( !isOpen() ) { +#ifdef QT_CHECK_RANGE + qWarning( "QPSQLDriver::rollbackTransaction: Database not open" ); +#endif + return FALSE; + } + PGresult* res = PQexec( d->connection, "ROLLBACK" ); + if ( !res || PQresultStatus( res ) != PGRES_COMMAND_OK ) { + setLastError( qMakeError( "Could not rollback transaction", QSqlError::Transaction, d ) ); + PQclear( res ); + return FALSE; + } + PQclear( res ); + return TRUE; +} + +QStringList QPSQLDriver::tables( const QString& typeName ) const +{ + QStringList tl; + if ( !isOpen() ) + return tl; + int type = typeName.toInt(); + QSqlQuery t = createQuery(); + t.setForwardOnly( TRUE ); + + if ( typeName.isEmpty() || ((type & (int)QSql::Tables) == (int)QSql::Tables) ) { + + QString query("select relname from pg_class where (relkind = 'r') " + "and (relname !~ '^Inv') " + "and (relname !~ '^pg_') "); + if (pro >= QPSQLDriver::Version73) + query.append("and (relnamespace not in " + "(select oid from pg_namespace where nspname = 'information_schema')) " + "and pg_table_is_visible(pg_class.oid) "); + t.exec(query); + while ( t.next() ) + tl.append( t.value(0).toString() ); + } + if ( (type & (int)QSql::Views) == (int)QSql::Views ) { + QString query("select relname from pg_class where ( relkind = 'v' ) " + "and ( relname !~ '^Inv' ) " + "and ( relname !~ '^pg_' ) "); + if (pro >= QPSQLDriver::Version73) + query.append("and (relnamespace not in " + "(select oid from pg_namespace where nspname = 'information_schema')) " + "and pg_table_is_visible(pg_class.oid) "); + t.exec(query); + while ( t.next() ) + tl.append( t.value(0).toString() ); + } + if ( (type & (int)QSql::SystemTables) == (int)QSql::SystemTables ) { + QString query( "select relname from pg_class where ( relkind = 'r' ) " + "and ( relname like 'pg_%' ) " ); + if (pro >= QPSQLDriver::Version73) + query.append( "and pg_table_is_visible(pg_class.oid) " ); + t.exec(query); + while ( t.next() ) + tl.append( t.value(0).toString() ); + } + + return tl; +} + +QSqlIndex QPSQLDriver::primaryIndex( const QString& tablename ) const +{ + QSqlIndex idx( tablename ); + if ( !isOpen() ) + return idx; + QSqlQuery i = createQuery(); + QString stmt; + + switch( pro ) { + case QPSQLDriver::Version6: + stmt = "select pg_att1.attname, int(pg_att1.atttypid), pg_att2.attnum, pg_cl.relname " + "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " + "where lower(pg_cl.relname) = '%1_pkey' "; + break; + case QPSQLDriver::Version7: + case QPSQLDriver::Version71: + stmt = "select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname " + "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " + "where lower(pg_cl.relname) = '%1_pkey' "; + break; + case QPSQLDriver::Version73: + stmt = "select pg_att1.attname, pg_att1.atttypid::int, pg_cl.relname " + "from pg_attribute pg_att1, pg_attribute pg_att2, pg_class pg_cl, pg_index pg_ind " + "where lower(pg_cl.relname) = '%1_pkey' " + "and pg_table_is_visible(pg_cl.oid) " + "and pg_att1.attisdropped = false "; + break; + } + stmt += "and pg_cl.oid = pg_ind.indexrelid " + "and pg_att2.attrelid = pg_ind.indexrelid " + "and pg_att1.attrelid = pg_ind.indrelid " + "and pg_att1.attnum = pg_ind.indkey[pg_att2.attnum-1] " + "order by pg_att2.attnum"; + + i.exec( stmt.arg( tablename.lower() ) ); + while ( i.isActive() && i.next() ) { + QSqlField f( i.value(0).toString(), qDecodePSQLType( i.value(1).toInt() ) ); + idx.append( f ); + idx.setName( i.value(2).toString() ); + } + return idx; +} + +QSqlRecord QPSQLDriver::record( const QString& tablename ) const +{ + QSqlRecord fil; + if ( !isOpen() ) + return fil; + QString stmt; + switch( pro ) { + case QPSQLDriver::Version6: + stmt = "select pg_attribute.attname, int(pg_attribute.atttypid) " + "from pg_class, pg_attribute " + "where lower(pg_class.relname) = '%1' " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid "; + break; + case QPSQLDriver::Version7: + case QPSQLDriver::Version71: + stmt = "select pg_attribute.attname, pg_attribute.atttypid::int " + "from pg_class, pg_attribute " + "where lower(pg_class.relname) = '%1' " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid "; + break; + case QPSQLDriver::Version73: + stmt = "select pg_attribute.attname, pg_attribute.atttypid::int " + "from pg_class, pg_attribute " + "where lower(pg_class.relname) = '%1' " + "and pg_table_is_visible(pg_class.oid) " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attisdropped = false " + "and pg_attribute.attrelid = pg_class.oid "; + break; + } + + QSqlQuery fi = createQuery(); + fi.exec( stmt.arg( tablename.lower() ) ); + while ( fi.next() ) { + QSqlField f( fi.value(0).toString(), qDecodePSQLType( fi.value(1).toInt() ) ); + fil.append( f ); + } + return fil; +} + +QSqlRecord QPSQLDriver::record( const QSqlQuery& query ) const +{ + QSqlRecord fil; + if ( !isOpen() ) + return fil; + if ( query.isActive() && query.driver() == this ) { + QPSQLResult* result = (QPSQLResult*)query.result(); + int count = PQnfields( result->d->result ); + for ( int i = 0; i < count; ++i ) { + QString name = PQfname( result->d->result, i ); + QVariant::Type type = qDecodePSQLType( PQftype( result->d->result, i ) ); + QSqlField rf( name, type ); + fil.append( rf ); + } + } + return fil; +} + +QSqlRecordInfo QPSQLDriver::recordInfo( const QString& tablename ) const +{ + QSqlRecordInfo info; + if ( !isOpen() ) + return info; + + QString stmt; + switch( pro ) { + case QPSQLDriver::Version6: + stmt = "select pg_attribute.attname, int(pg_attribute.atttypid), pg_attribute.attnotnull, " + "pg_attribute.attlen, pg_attribute.atttypmod, int(pg_attribute.attrelid), pg_attribute.attnum " + "from pg_class, pg_attribute " + "where lower(pg_class.relname) = '%1' " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid "; + break; + case QPSQLDriver::Version7: + stmt = "select pg_attribute.attname, pg_attribute.atttypid::int, pg_attribute.attnotnull, " + "pg_attribute.attlen, pg_attribute.atttypmod, pg_attribute.attrelid::int, pg_attribute.attnum " + "from pg_class, pg_attribute " + "where lower(pg_class.relname) = '%1' " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid "; + break; + case QPSQLDriver::Version71: + stmt = "select pg_attribute.attname, pg_attribute.atttypid::int, pg_attribute.attnotnull, " + "pg_attribute.attlen, pg_attribute.atttypmod, pg_attrdef.adsrc " + "from pg_class, pg_attribute " + "left join pg_attrdef on (pg_attrdef.adrelid = pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) " + "where lower(pg_class.relname) = '%1' " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid " + "order by pg_attribute.attnum "; + break; + case QPSQLDriver::Version73: + stmt = "select pg_attribute.attname, pg_attribute.atttypid::int, pg_attribute.attnotnull, " + "pg_attribute.attlen, pg_attribute.atttypmod, pg_attrdef.adsrc " + "from pg_class, pg_attribute " + "left join pg_attrdef on (pg_attrdef.adrelid = pg_attribute.attrelid and pg_attrdef.adnum = pg_attribute.attnum) " + "where lower(pg_class.relname) = '%1' " + "and pg_table_is_visible(pg_class.oid) " + "and pg_attribute.attnum > 0 " + "and pg_attribute.attrelid = pg_class.oid " + "and pg_attribute.attisdropped = false " + "order by pg_attribute.attnum "; + break; + } + + QSqlQuery query = createQuery(); + query.exec( stmt.arg( tablename.lower() ) ); + if ( pro >= QPSQLDriver::Version71 ) { + while ( query.next() ) { + int len = query.value( 3 ).toInt(); + int precision = query.value( 4 ).toInt(); + // swap length and precision if length == -1 + if ( len == -1 && precision > -1 ) { + len = precision - 4; + precision = -1; + } + QString defVal = query.value( 5 ).toString(); + if ( !defVal.isEmpty() && defVal.startsWith( "'" ) ) + defVal = defVal.mid( 1, defVal.length() - 2 ); + info.append( QSqlFieldInfo( query.value( 0 ).toString(), + qDecodePSQLType( query.value( 1 ).toInt() ), + query.value( 2 ).toBool(), + len, + precision, + defVal, + query.value( 1 ).toInt() ) ); + } + } else { + // Postgres < 7.1 cannot handle outer joins + while ( query.next() ) { + QString defVal; + QString stmt2 = "select pg_attrdef.adsrc from pg_attrdef where " + "pg_attrdef.adrelid = %1 and pg_attrdef.adnum = %2 "; + QSqlQuery query2 = createQuery(); + query2.exec( stmt2.arg( query.value( 5 ).toInt() ).arg( query.value( 6 ).toInt() ) ); + if ( query2.isActive() && query2.next() ) + defVal = query2.value( 0 ).toString(); + if ( !defVal.isEmpty() && defVal.startsWith( "'" ) ) + defVal = defVal.mid( 1, defVal.length() - 2 ); + int len = query.value( 3 ).toInt(); + int precision = query.value( 4 ).toInt(); + // swap length and precision if length == -1 + if ( len == -1 && precision > -1 ) { + len = precision - 4; + precision = -1; + } + info.append( QSqlFieldInfo( query.value( 0 ).toString(), + qDecodePSQLType( query.value( 1 ).toInt() ), + query.value( 2 ).toBool(), + len, + precision, + defVal, + query.value( 1 ).toInt() ) ); + } + } + + return info; +} + +QSqlRecordInfo QPSQLDriver::recordInfo( const QSqlQuery& query ) const +{ + QSqlRecordInfo info; + if ( !isOpen() ) + return info; + if ( query.isActive() && query.driver() == this ) { + QPSQLResult* result = (QPSQLResult*)query.result(); + int count = PQnfields( result->d->result ); + for ( int i = 0; i < count; ++i ) { + QString name = PQfname( result->d->result, i ); + int len = PQfsize( result->d->result, i ); + int precision = PQfmod( result->d->result, i ); + // swap length and precision if length == -1 + if ( len == -1 && precision > -1 ) { + len = precision - 4; + precision = -1; + } + info.append( QSqlFieldInfo( name, + qDecodePSQLType( PQftype( result->d->result, i ) ), + -1, + len, + precision, + QVariant(), + PQftype( result->d->result, i ) ) ); + } + } + return info; +} + +QString QPSQLDriver::formatValue( const QSqlField* field, + bool ) const +{ + QString r; + if ( field->isNull() ) { + r = nullText(); + } else { + switch ( field->type() ) { + case QVariant::DateTime: + if ( field->value().toDateTime().isValid() ) { + QDate dt = field->value().toDateTime().date(); + QTime tm = field->value().toDateTime().time(); + // msecs need to be right aligned otherwise psql + // interpretes them wrong + r = "'" + QString::number( dt.year() ) + "-" + + QString::number( dt.month() ) + "-" + + QString::number( dt.day() ) + " " + + tm.toString() + "." + + QString::number( tm.msec() ).rightJustify( 3, '0' ) + "'"; + } else { + r = nullText(); + } + break; + case QVariant::Time: + if ( field->value().toTime().isValid() ) { + r = field->value().toTime().toString( Qt::ISODate ); + } else { + r = nullText(); + } + case QVariant::String: + case QVariant::CString: { + switch ( field->value().type() ) { + case QVariant::Rect: { + QRect rec = field->value().toRect(); + // upper right corner then lower left according to psql docs + r = "'(" + QString::number( rec.right() ) + + "," + QString::number( rec.bottom() ) + + "),(" + QString::number( rec.left() ) + + "," + QString::number( rec.top() ) + ")'"; + break; + } + case QVariant::Point: { + QPoint p = field->value().toPoint(); + r = "'(" + QString::number( p.x() ) + + "," + QString::number( p.y() ) + ")'"; + break; + } + case QVariant::PointArray: { + QPointArray pa = field->value().toPointArray(); + r = "' "; + for ( int i = 0; i < (int)pa.size(); ++i ) { + r += "(" + QString::number( pa[i].x() ) + + "," + QString::number( pa[i].y() ) + "),"; + } + r.truncate( r.length() - 1 ); + r += "'"; + break; + } + default: + // Escape '\' characters + r = QSqlDriver::formatValue( field ); + r.replace( "\\", "\\\\" ); + break; + } + break; + } + case QVariant::Bool: + if ( field->value().toBool() ) + r = "TRUE"; + else + r = "FALSE"; + break; + case QVariant::ByteArray: { + QByteArray ba = field->value().asByteArray(); + QString res; + r = "'"; + unsigned char uc; + for ( int i = 0; i < (int)ba.size(); ++i ) { + uc = (unsigned char) ba[ i ]; + if ( uc > 40 && uc < 92 ) { + r += uc; + } else { + r += "\\\\"; + r += QString::number( (unsigned char) ba[ i ], 8 ).rightJustify( 3, '0', TRUE ); + } + } + r += "'"; + break; + } + default: + r = QSqlDriver::formatValue( field ); + break; + } + } + return r; +} diff --git a/main/dependencies/qt3/src/sql/drivers/psql/qsql_psql.h b/main/dependencies/qt3/src/sql/drivers/psql/qsql_psql.h new file mode 100644 index 000000000..fd9cbe617 --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/psql/qsql_psql.h @@ -0,0 +1,131 @@ +/**************************************************************************** +** +** Definition of PostgreSQL driver classes +** +** Created : 001103 +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQL_PSQL_H +#define QSQL_PSQL_H + +#include <qsqlresult.h> +#include <qsqlfield.h> +#include <qsqldriver.h> +#include <libpq-fe.h> + +#ifdef QT_PLUGIN +#define Q_EXPORT_SQLDRIVER_PSQL +#else +#define Q_EXPORT_SQLDRIVER_PSQL Q_EXPORT +#endif + +class QPSQLPrivate; +class QPSQLDriver; +class QSqlRecordInfo; + +class QPSQLResult : public QSqlResult +{ + friend class QPSQLDriver; +public: + QPSQLResult( const QPSQLDriver* db, const QPSQLPrivate* p ); + ~QPSQLResult(); + PGresult* result(); +protected: + void cleanup(); + bool fetch( int i ); + bool fetchFirst(); + bool fetchLast(); + QVariant data( int i ); + bool isNull( int field ); + bool reset ( const QString& query ); + int size(); + int numRowsAffected(); +private: + int currentSize; + QPSQLPrivate* d; +}; + +class Q_EXPORT_SQLDRIVER_PSQL QPSQLDriver : public QSqlDriver +{ +public: + enum Protocol { + Version6 = 6, + Version7 = 7, + Version71 = 8, + Version73 = 9 + }; + + QPSQLDriver( QObject * parent=0, const char * name=0 ); + QPSQLDriver( PGconn * conn, QObject * parent=0, const char * name=0 ); + ~QPSQLDriver(); + bool hasFeature( DriverFeature f ) const; + bool open( const QString & db, + const QString & user = QString::null, + const QString & password = QString::null, + const QString & host = QString::null, + int port = -1 ); + void close(); + QSqlQuery createQuery() const; + QStringList tables( const QString& user ) const; + QSqlIndex primaryIndex( const QString& tablename ) const; + QSqlRecord record( const QString& tablename ) const; + QSqlRecord record( const QSqlQuery& query ) const; + QSqlRecordInfo recordInfo( const QString& tablename ) const; + QSqlRecordInfo recordInfo( const QSqlQuery& query ) const; + + Protocol protocol() const { return pro; } + PGconn* connection(); + QString formatValue( const QSqlField* field, + bool trimStrings ) const; + + // ### remove me for 4.0 + bool open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ); +protected: + bool beginTransaction(); + bool commitTransaction(); + bool rollbackTransaction(); +private: + void init(); + Protocol pro; + QPSQLPrivate* d; +}; + +#endif diff --git a/main/dependencies/qt3/src/sql/drivers/sqlite/qsql_sqlite.cpp b/main/dependencies/qt3/src/sql/drivers/sqlite/qsql_sqlite.cpp new file mode 100644 index 000000000..f8c7ffaa0 --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/sqlite/qsql_sqlite.cpp @@ -0,0 +1,513 @@ +/**************************************************************************** +** +** Implementation of SQLite driver classes. +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** EDITIONS: FREE, ENTERPRISE +** +** 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 "qsql_sqlite.h" + +#include <qdatetime.h> +#include <qregexp.h> +#include <qfile.h> + +#if (QT_VERSION-0 < 0x030000) +# include <qvector.h> +# if !defined Q_WS_WIN32 +# include <unistd.h> +# endif +# include "../../../3rdparty/libraries/sqlite/sqlite.h" +#else +# include <qptrvector.h> +# if !defined Q_WS_WIN32 +# include <unistd.h> +# endif +# include <sqlite.h> +#endif + +typedef struct sqlite_vm sqlite_vm; + +#define QSQLITE_DRIVER_NAME "QSQLITE" + +static QSqlVariant::Type nameToType(const QString& typeName) +{ + QString tName = typeName.upper(); + if (tName.startsWith("INT")) + return QSqlVariant::Int; + if (tName.startsWith("FLOAT") || tName.startsWith("NUMERIC")) + return QSqlVariant::Double; + if (tName.startsWith("BOOL")) + return QSqlVariant::Bool; + // SQLite is typeless - consider everything else as string + return QSqlVariant::String; +} + +class QSQLiteDriverPrivate +{ +public: + QSQLiteDriverPrivate(); + sqlite *access; + bool utf8; +}; + +QSQLiteDriverPrivate::QSQLiteDriverPrivate() : access(0) +{ + utf8 = (qstrcmp(sqlite_encoding, "UTF-8") == 0); +} + +class QSQLiteResultPrivate +{ +public: + QSQLiteResultPrivate(QSQLiteResult *res); + void cleanup(); + bool fetchNext(QtSqlCachedResult::RowCache *row); + bool isSelect(); + // initializes the recordInfo and the cache + void init(const char **cnames, int numCols, QtSqlCachedResult::RowCache **row = 0); + void finalize(); + + QSQLiteResult* q; + sqlite *access; + + // and we have too keep our own struct for the data (sqlite works via + // callback. + const char *currentTail; + sqlite_vm *currentMachine; + + uint skippedStatus: 1; // the status of the fetchNext() that's skipped + QtSqlCachedResult::RowCache *skipRow; + + uint utf8: 1; + QSqlRecordInfo rInf; +}; + +static const uint initial_cache_size = 128; + +QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult* res) : q(res), access(0), currentTail(0), + currentMachine(0), skippedStatus(FALSE), skipRow(0), utf8(FALSE) +{ +} + +void QSQLiteResultPrivate::cleanup() +{ + finalize(); + rInf.clear(); + currentTail = 0; + currentMachine = 0; + skippedStatus = FALSE; + delete skipRow; + skipRow = 0; + q->setAt(QSql::BeforeFirst); + q->setActive(FALSE); + q->cleanup(); +} + +void QSQLiteResultPrivate::finalize() +{ + if (!currentMachine) + return; + + char* err = 0; + int res = sqlite_finalize(currentMachine, &err); + if (err) { + q->setLastError(QSqlError("Unable to fetch results", err, QSqlError::Statement, res)); + sqlite_freemem(err); + } + currentMachine = 0; +} + +// called on first fetch +void QSQLiteResultPrivate::init(const char **cnames, int numCols, QtSqlCachedResult::RowCache **row) +{ + if (!cnames) + return; + + rInf.clear(); + if (numCols <= 0) + return; + + for (int i = 0; i < numCols; ++i) { + const char* lastDot = strrchr(cnames[i], '.'); + const char* fieldName = lastDot ? lastDot + 1 : cnames[i]; + rInf.append(QSqlFieldInfo(fieldName, nameToType(cnames[i+numCols]))); + } + // skip the first fetch + if (row && !*row) { + *row = new QtSqlCachedResult::RowCache(numCols); + skipRow = *row; + } +} + +bool QSQLiteResultPrivate::fetchNext(QtSqlCachedResult::RowCache* row) +{ + // may be caching. + const char **fvals; + const char **cnames; + int colNum; + int res; + int i; + + if (skipRow) { + // already fetched + if (row) + *row = *skipRow; + delete skipRow; + skipRow = 0; + return skippedStatus; + } + + if (!currentMachine) + return FALSE; + + // keep trying while busy, wish I could implement this better. + while ((res = sqlite_step(currentMachine, &colNum, &fvals, &cnames)) == SQLITE_BUSY) { + // sleep instead requesting result again immidiately. +#if defined Q_WS_WIN32 + Sleep(1000); +#else + sleep(1); +#endif + } + + switch(res) { + case SQLITE_ROW: + // check to see if should fill out columns + if (rInf.isEmpty()) + // must be first call. + init(cnames, colNum, &row); + if (!fvals) + return FALSE; + if (!row) + return TRUE; + for (i = 0; i < colNum; ++i) + (*row)[i] = utf8 ? QString::fromUtf8(fvals[i]) : QString(fvals[i]); + return TRUE; + case SQLITE_DONE: + if (rInf.isEmpty()) + // must be first call. + init(cnames, colNum); + q->setAt(QSql::AfterLast); + return FALSE; + case SQLITE_ERROR: + case SQLITE_MISUSE: + default: + // something wrong, don't get col info, but still return false + finalize(); // finalize to get the error message. + q->setAt(QSql::AfterLast); + return FALSE; + } + return FALSE; +} + +QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db) +: QtSqlCachedResult(db) +{ + d = new QSQLiteResultPrivate(this); + d->access = db->d->access; + d->utf8 = db->d->utf8; +} + +QSQLiteResult::~QSQLiteResult() +{ + d->cleanup(); + delete d; +} + +/* + Execute \a query. +*/ +bool QSQLiteResult::reset (const QString& query) +{ + // this is where we build a query. + if (!driver()) + return FALSE; + if (!driver()-> isOpen() || driver()->isOpenError()) + return FALSE; + + d->cleanup(); + + // Um, ok. callback based so.... pass private static function for this. + setSelect(FALSE); + char *err = 0; + int res = sqlite_compile(d->access, + d->utf8 ? (const char*)query.utf8().data() : query.ascii(), + &(d->currentTail), + &(d->currentMachine), + &err); + if (res != SQLITE_OK || err) { + setLastError(QSqlError("Unable to execute statement", err, QSqlError::Statement, res)); + sqlite_freemem(err); + } + //if (*d->currentTail != '\000' then there is more sql to eval + if (!d->currentMachine) { + setActive(FALSE); + return FALSE; + } + // we have to fetch one row to find out about + // the structure of the result set + d->skippedStatus = d->fetchNext(0); + setSelect(!d->rInf.isEmpty()); + if (isSelect()) + init(d->rInf.count()); + setActive(TRUE); + return TRUE; +} + +bool QSQLiteResult::gotoNext(QtSqlCachedResult::RowCache* row) +{ + return d->fetchNext(row); +} + +int QSQLiteResult::size() +{ + return -1; +} + +int QSQLiteResult::numRowsAffected() +{ + return sqlite_changes(d->access); +} + +///////////////////////////////////////////////////////// + +QSQLiteDriver::QSQLiteDriver(QObject * parent, const char * name) + : QSqlDriver(parent, name ? name : QSQLITE_DRIVER_NAME) +{ + d = new QSQLiteDriverPrivate(); +} + +QSQLiteDriver::QSQLiteDriver(sqlite *connection, QObject *parent, const char *name) + : QSqlDriver(parent, name ? name : QSQLITE_DRIVER_NAME) +{ + d = new QSQLiteDriverPrivate(); + d->access = connection; + setOpen(TRUE); + setOpenError(FALSE); +} + + +QSQLiteDriver::~QSQLiteDriver() +{ + delete d; +} + +bool QSQLiteDriver::hasFeature(DriverFeature f) const +{ + switch (f) { + case Transactions: + return TRUE; +#if (QT_VERSION-0 >= 0x030000) + case Unicode: + return d->utf8; +#endif +// case BLOB: + default: + return FALSE; + } +} + +/* + SQLite dbs have no user name, passwords, hosts or ports. + just file names. +*/ +bool QSQLiteDriver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &) +{ + if (isOpen()) + close(); + + if (db.isEmpty()) + return FALSE; + + char* err = 0; + d->access = sqlite_open(QFile::encodeName(db), 0, &err); + if (err) { + setLastError(QSqlError("Error to open database", err, QSqlError::Connection)); + sqlite_freemem(err); + err = 0; + } + + if (d->access) { + setOpen(TRUE); + setOpenError(FALSE); + return TRUE; + } + setOpenError(TRUE); + return FALSE; +} + +void QSQLiteDriver::close() +{ + if (isOpen()) { + sqlite_close(d->access); + d->access = 0; + setOpen(FALSE); + setOpenError(FALSE); + } +} + +QSqlQuery QSQLiteDriver::createQuery() const +{ + return QSqlQuery(new QSQLiteResult(this)); +} + +bool QSQLiteDriver::beginTransaction() +{ + if (!isOpen() || isOpenError()) + return FALSE; + + char* err; + int res = sqlite_exec(d->access, "BEGIN", 0, this, &err); + + if (res == SQLITE_OK) + return TRUE; + + setLastError(QSqlError("Unable to begin transaction", err, QSqlError::Transaction, res)); + sqlite_freemem(err); + return FALSE; +} + +bool QSQLiteDriver::commitTransaction() +{ + if (!isOpen() || isOpenError()) + return FALSE; + + char* err; + int res = sqlite_exec(d->access, "COMMIT", 0, this, &err); + + if (res == SQLITE_OK) + return TRUE; + + setLastError(QSqlError("Unable to commit transaction", err, QSqlError::Transaction, res)); + sqlite_freemem(err); + return FALSE; +} + +bool QSQLiteDriver::rollbackTransaction() +{ + if (!isOpen() || isOpenError()) + return FALSE; + + char* err; + int res = sqlite_exec(d->access, "ROLLBACK", 0, this, &err); + + if (res == SQLITE_OK) + return TRUE; + + setLastError(QSqlError("Unable to rollback Transaction", err, QSqlError::Transaction, res)); + sqlite_freemem(err); + return FALSE; +} + +QStringList QSQLiteDriver::tables(const QString &typeName) const +{ + QStringList res; + if (!isOpen()) + return res; + int type = typeName.toInt(); + + QSqlQuery q = createQuery(); + q.setForwardOnly(TRUE); +#if (QT_VERSION-0 >= 0x030000) + if ((type & (int)QSql::Tables) && (type & (int)QSql::Views)) + q.exec("SELECT name FROM sqlite_master WHERE type='table' OR type='view'"); + else if (typeName.isEmpty() || (type & (int)QSql::Tables)) + q.exec("SELECT name FROM sqlite_master WHERE type='table'"); + else if (type & (int)QSql::Views) + q.exec("SELECT name FROM sqlite_master WHERE type='view'"); +#else + q.exec("SELECT name FROM sqlite_master WHERE type='table' OR type='view'"); +#endif + + + if (q.isActive()) { + while(q.next()) + res.append(q.value(0).toString()); + } + +#if (QT_VERSION-0 >= 0x030000) + if (type & (int)QSql::SystemTables) { + // there are no internal tables beside this one: + res.append("sqlite_master"); + } +#endif + + return res; +} + +QSqlIndex QSQLiteDriver::primaryIndex(const QString &tblname) const +{ + QSqlRecordInfo rec(recordInfo(tblname)); // expensive :( + + if (!isOpen()) + return QSqlIndex(); + + QSqlQuery q = createQuery(); + q.setForwardOnly(TRUE); + // finrst find a UNIQUE INDEX + q.exec("PRAGMA index_list('" + tblname + "');"); + QString indexname; + while(q.next()) { + if (q.value(2).toInt()==1) { + indexname = q.value(1).toString(); + break; + } + } + if (indexname.isEmpty()) + return QSqlIndex(); + + q.exec("PRAGMA index_info('" + indexname + "');"); + + QSqlIndex index(tblname, indexname); + while(q.next()) { + QString name = q.value(2).toString(); + QSqlVariant::Type type = QSqlVariant::Invalid; + if (rec.contains(name)) + type = rec.find(name).type(); + index.append(QSqlField(name, type)); + } + return index; +} + +QSqlRecordInfo QSQLiteDriver::recordInfo(const QString &tbl) const +{ + if (!isOpen()) + return QSqlRecordInfo(); + + QSqlQuery q = createQuery(); + q.setForwardOnly(TRUE); + q.exec("SELECT * FROM " + tbl + " LIMIT 1"); + return recordInfo(q); +} + +QSqlRecord QSQLiteDriver::record(const QString &tblname) const +{ + if (!isOpen()) + return QSqlRecord(); + + return recordInfo(tblname).toRecord(); +} + +QSqlRecord QSQLiteDriver::record(const QSqlQuery& query) const +{ + if (query.isActive() && query.driver() == this) { + QSQLiteResult* result = (QSQLiteResult*)query.result(); + return result->d->rInf.toRecord(); + } + return QSqlRecord(); +} + +QSqlRecordInfo QSQLiteDriver::recordInfo(const QSqlQuery& query) const +{ + if (query.isActive() && query.driver() == this) { + QSQLiteResult* result = (QSQLiteResult*)query.result(); + return result->d->rInf; + } + return QSqlRecordInfo(); +} diff --git a/main/dependencies/qt3/src/sql/drivers/sqlite/qsql_sqlite.h b/main/dependencies/qt3/src/sql/drivers/sqlite/qsql_sqlite.h new file mode 100644 index 000000000..f3b919263 --- /dev/null +++ b/main/dependencies/qt3/src/sql/drivers/sqlite/qsql_sqlite.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Definition of SQLite driver classes. +** +** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** EDITIONS: FREE, ENTERPRISE +** +** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +** +****************************************************************************/ + +#ifndef QSQL_SQLITE_H +#define QSQL_SQLITE_H + +#include <qsqldriver.h> +#include <qsqlresult.h> +#include <qsqlrecord.h> +#include <qsqlindex.h> +#include "../cache/qsqlcachedresult.h" + +#if (QT_VERSION-0 >= 0x030000) +typedef QVariant QSqlVariant; +#endif + +#if defined (Q_OS_WIN32) +# include <qt_windows.h> +#endif + +class QSQLiteDriverPrivate; +class QSQLiteResultPrivate; +class QSQLiteDriver; +struct sqlite; + +class QSQLiteResult : public QtSqlCachedResult +{ + friend class QSQLiteDriver; + friend class QSQLiteResultPrivate; +public: + QSQLiteResult(const QSQLiteDriver* db); + ~QSQLiteResult(); + +protected: + bool gotoNext(QtSqlCachedResult::RowCache* row); + bool reset (const QString& query); + int size(); + int numRowsAffected(); + +private: + QSQLiteResultPrivate* d; +}; + +class QSQLiteDriver : public QSqlDriver +{ + friend class QSQLiteResult; +public: + QSQLiteDriver(QObject *parent = 0, const char *name = 0); + QSQLiteDriver(sqlite *connection, QObject *parent = 0, const char *name = 0); + ~QSQLiteDriver(); + bool hasFeature(DriverFeature f) const; + bool open(const QString & db, + const QString & user, + const QString & password, + const QString & host, + int port, + const QString & connOpts); + bool open( const QString & db, + const QString & user, + const QString & password, + const QString & host, + int port ) { return open (db, user, password, host, port, QString()); } + void close(); + QSqlQuery createQuery() const; + bool beginTransaction(); + bool commitTransaction(); + bool rollbackTransaction(); + QStringList tables(const QString& user) const; + + QSqlRecord record(const QString& tablename) const; + QSqlRecordInfo recordInfo(const QString& tablename) const; + QSqlIndex primaryIndex(const QString &table) const; + QSqlRecord record(const QSqlQuery& query) const; + QSqlRecordInfo recordInfo(const QSqlQuery& query) const; + +private: + QSQLiteDriverPrivate* d; +}; +#endif diff --git a/main/dependencies/qt3/src/sql/qdatabrowser.cpp b/main/dependencies/qt3/src/sql/qdatabrowser.cpp new file mode 100644 index 000000000..a09430cec --- /dev/null +++ b/main/dependencies/qt3/src/sql/qdatabrowser.cpp @@ -0,0 +1,1284 @@ +/**************************************************************************** +** +** Implementation of QDataBrowser class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qdatabrowser.h" + +#ifndef QT_NO_SQL_VIEW_WIDGETS + +#include "qsqlform.h" +#include "qsqlmanager_p.h" +#include "qsqlresult.h" + +class QDataBrowserPrivate +{ +public: + QDataBrowserPrivate() : boundaryCheck( TRUE ), readOnly( FALSE ) {} + QSqlCursorManager cur; + QSqlFormManager frm; + QDataManager dat; + bool boundaryCheck; + bool readOnly; +}; + +/*! + \class QDataBrowser qdatabrowser.h + \brief The QDataBrowser class provides data manipulation and + navigation for data entry forms. + + \ingroup database + \mainclass + \module sql + + A high-level API is provided for navigating through data records + in a cursor, for inserting, updating and deleting records, and for + refreshing data in the display. + + If you want a read-only form to present database data use + QDataView; if you want a table-based presentation of your data use + QDataTable. + + A QDataBrowser is used to associate a dataset with a form in much + the same way as a QDataTable associates a dataset with a table. + Once the data browser has been constructed it can be associated + with a dataset with setSqlCursor(), and with a form with + setForm(). Boundary checking, sorting and filtering can be set + with setBoundaryChecking(), setSort() and setFilter(), + respectively. + + The insertCurrent() function reads the fields from the default + form into the default cursor and performs the insert. The + updateCurrent() and deleteCurrent() functions perform similarly to + update and delete the current record respectively. + + The user can be asked to confirm all edits with setConfirmEdits(). + For more precise control use setConfirmInsert(), + setConfirmUpdate(), setConfirmDelete() and setConfirmCancels(). + Use setAutoEdit() to control the behaviour of the form when the + user edits a record and then navigates. + + The record set is navigated using first(), next(), prev(), last() + and seek(). The form's display is updated with refresh(). When + navigation takes place the firstRecordAvailable(), + lastRecordAvailable(), nextRecordAvailable() and + prevRecordAvailable() signals are emitted. When the cursor record + is changed due to navigation the cursorChanged() signal is + emitted. + + If you want finer control of the insert, update and delete + processes then you can use the lower level functions to perform + these operations as described below. + + The form is populated with data from the database with + readFields(). If the user is allowed to edit, (see setReadOnly()), + write the form's data back to the cursor's edit buffer with + writeFields(). You can clear the values in the form with + clearValues(). Editing is performed as follows: + \list + \i \e insert When the data browser enters insertion mode it emits the + primeInsert() signal which you can connect to, for example to + pre-populate fields. Call writeFields() to write the user's edits to + the cursor's edit buffer then call insert() to insert the record + into the database. The beforeInsert() signal is emitted just before + the cursor's edit buffer is inserted into the database; connect to + this for example, to populate fields such as an auto-generated + primary key. + \i \e update For updates the primeUpdate() signal is emitted when + the data browser enters update mode. After calling writeFields() + call update() to update the record and connect to the beforeUpdate() + signal to manipulate the user's data before the update takes place. + \i \e delete For deletion the primeDelete() signal is emitted when + the data browser enters deletion mode. After calling writeFields() + call del() to delete the record and connect to the beforeDelete() + signal, for example to record an audit of the deleted record. + \endlist + +*/ + +/*! + \enum QDataBrowser::Boundary + + This enum describes where the data browser is positioned. + + \value Unknown the boundary cannot be determined (usually because + there is no default cursor, or the default cursor is not active). + + \value None the browser is not positioned on a boundary, but it is + positioned on a record somewhere in the middle. + + \value BeforeBeginning the browser is positioned before the + first available record. + + \value Beginning the browser is positioned at the first record. + + \value End the browser is positioned at the last + record. + + \value AfterEnd the browser is positioned after the last + available record. +*/ + +/*! + Constructs a data browser which is a child of \a parent, with the + name \a name and widget flags set to \a fl. +*/ + +QDataBrowser::QDataBrowser( QWidget *parent, const char *name, WFlags fl ) + : QWidget( parent, name, fl ) +{ + d = new QDataBrowserPrivate(); + d->dat.setMode( QSql::Update ); +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QDataBrowser::~QDataBrowser() +{ + delete d; +} + + +/*! + Returns an enum indicating the boundary status of the browser. + + This is achieved by moving the default cursor and checking the + position, however the current default form values will not be + altered. After checking for the boundary, the cursor is moved back + to its former position. See \l QDataBrowser::Boundary. + + \sa Boundary +*/ + +QDataBrowser::Boundary QDataBrowser::boundary() +{ + QSqlCursor* cur = d->cur.cursor(); + if ( !cur || !cur->isActive() ) + return Unknown; + if ( !cur->isValid() ) { + if ( cur->at() == QSql::BeforeFirst ) + return BeforeBeginning; + if ( cur->at() == QSql::AfterLast ) + return AfterEnd; + return Unknown; + } + if ( cur->at() == 0 ) + return Beginning; + int currentAt = cur->at(); + + Boundary b = None; + if ( !cur->prev() ) + b = Beginning; + else + cur->seek( currentAt ); + if ( b == None && !cur->next() ) + b = End; + cur->seek( currentAt ); + return b; +} + + +/*! + \property QDataBrowser::boundaryChecking + \brief whether boundary checking is active + + When boundary checking is active (the default), signals are + emitted indicating the current position of the default cursor. + + \sa boundary() +*/ + +void QDataBrowser::setBoundaryChecking( bool active ) +{ + d->boundaryCheck = active; +} + +bool QDataBrowser::boundaryChecking() const +{ + return d->boundaryCheck; +} + +/*! + \property QDataBrowser::sort + \brief the data browser's sort + + The data browser's sort affects the order in which records are + viewed in the browser. Call refresh() to apply the new sort. + + When retrieving the sort property, a string list is returned in + the form 'fieldname order', e.g. 'id ASC', 'surname DESC'. + + There is no default sort. + + Note that if you want to iterate over the list, you should iterate + over a copy, e.g. + \code + QStringList list = myDataBrowser.sort(); + QStringList::Iterator it = list.begin(); + while( it != list.end() ) { + myProcessing( *it ); + ++it; + } + \endcode +*/ + +void QDataBrowser::setSort( const QStringList& sort ) +{ + d->cur.setSort( sort ); +} + +/*! + \overload + + Sets the data browser's sort to the QSqlIndex \a sort. To apply + the new sort, use refresh(). + +*/ +void QDataBrowser::setSort( const QSqlIndex& sort ) +{ + d->cur.setSort( sort ); +} + +QStringList QDataBrowser::sort() const +{ + return d->cur.sort(); +} + + +/*! + \property QDataBrowser::filter + \brief the data browser's filter + + The filter applies to the data shown in the browser. Call + refresh() to apply the new filter. A filter is a string containing + a SQL WHERE clause without the WHERE keyword, e.g. "id>1000", + "name LIKE 'A%'", etc. + + There is no default filter. + + \sa sort() +*/ + +void QDataBrowser::setFilter( const QString& filter ) +{ + d->cur.setFilter( filter ); +} + + +QString QDataBrowser::filter() const +{ + return d->cur.filter(); +} + + +/*! + Sets the default cursor used by the data browser to \a cursor. If + \a autoDelete is TRUE (the default is FALSE), the data browser + takes ownership of the \a cursor pointer, which will be deleted + when the browser is destroyed, or when setSqlCursor() is called + again. To activate the \a cursor use refresh(). The cursor's edit + buffer is used in the default form to browse and edit records. + + \sa sqlCursor() form() setForm() +*/ + +void QDataBrowser::setSqlCursor( QSqlCursor* cursor, bool autoDelete ) +{ + if ( !cursor ) + return; + d->cur.setCursor( cursor, autoDelete ); + d->frm.setRecord( cursor->editBuffer() ); + if ( cursor->isReadOnly() ) + setReadOnly( TRUE ); +} + + +/*! + Returns the default cursor used for navigation, or 0 if there is + no default cursor. + + \sa setSqlCursor() +*/ + +QSqlCursor* QDataBrowser::sqlCursor() const +{ + return d->cur.cursor(); +} + + +/*! + Sets the browser's default form to \a form. The cursor and all + navigation and data manipulation functions that the browser + provides become available to the \a form. +*/ + +void QDataBrowser::setForm( QSqlForm* form ) +{ + d->frm.setForm( form ); +} + + +/*! + Returns the data browser's default form or 0 if no form has been + set. +*/ + +QSqlForm* QDataBrowser::form() +{ + return d->frm.form(); +} + +/*! + \property QDataBrowser::readOnly + \brief whether the browser is read-only + + The default is FALSE, i.e. data can be edited. If the data browser + is read-only, no database edits will be allowed. +*/ + +void QDataBrowser::setReadOnly( bool active ) +{ + d->readOnly = active; +} + +bool QDataBrowser::isReadOnly() const +{ + return d->readOnly; +} + +void QDataBrowser::setConfirmEdits( bool confirm ) +{ + d->dat.setConfirmEdits( confirm ); +} + +/*! + \property QDataBrowser::confirmInsert + \brief whether the data browser confirms insertions + + If this property is TRUE, the browser confirms insertions, + otherwise insertions happen immediately. + + \sa confirmCancels() confirmEdits() confirmUpdate() confirmDelete() confirmEdit() +*/ + +void QDataBrowser::setConfirmInsert( bool confirm ) +{ + d->dat.setConfirmInsert( confirm ); +} + +/*! + \property QDataBrowser::confirmUpdate + \brief whether the browser confirms updates + + If this property is TRUE, the browser confirms updates, otherwise + updates happen immediately. + + \sa confirmCancels() confirmEdits() confirmInsert() confirmDelete() confirmEdit() +*/ + +void QDataBrowser::setConfirmUpdate( bool confirm ) +{ + d->dat.setConfirmUpdate( confirm ); +} + +/*! + \property QDataBrowser::confirmDelete + \brief whether the browser confirms deletions + + If this property is TRUE, the browser confirms deletions, + otherwise deletions happen immediately. + + \sa confirmCancels() confirmEdits() confirmUpdate() confirmInsert() confirmEdit() +*/ + +void QDataBrowser::setConfirmDelete( bool confirm ) +{ + d->dat.setConfirmDelete( confirm ); +} + +/*! + \property QDataBrowser::confirmEdits + \brief whether the browser confirms edits + + If this property is TRUE, the browser confirms all edit operations + (insertions, updates and deletions), otherwise all edit operations + happen immediately. Confirmation is achieved by presenting the + user with a message box -- this behavior can be changed by + reimplementing the confirmEdit() function, + + \sa confirmEdit() confirmCancels() confirmInsert() confirmUpdate() confirmDelete() +*/ + +bool QDataBrowser::confirmEdits() const +{ + return ( d->dat.confirmEdits() ); +} + +bool QDataBrowser::confirmInsert() const +{ + return ( d->dat.confirmInsert() ); +} + +bool QDataBrowser::confirmUpdate() const +{ + return ( d->dat.confirmUpdate() ); +} + +bool QDataBrowser::confirmDelete() const +{ + return ( d->dat.confirmDelete() ); +} + +/*! + \property QDataBrowser::confirmCancels + \brief whether the browser confirms cancel operations + + If this property is TRUE, all cancels must be confirmed by the + user through a message box (this behavior can be changed by + overriding the confirmCancel() function), otherwise all cancels + occur immediately. The default is FALSE. + + \sa confirmEdits() confirmCancel() +*/ + +void QDataBrowser::setConfirmCancels( bool confirm ) +{ + d->dat.setConfirmCancels( confirm ); +} + +bool QDataBrowser::confirmCancels() const +{ + return d->dat.confirmCancels(); +} + +/*! + \property QDataBrowser::autoEdit + \brief whether the browser automatically applies edits + + The default value for this property is TRUE. When the user begins + an insertion or an update on a form there are two possible + outcomes when they navigate to another record: + + \list + \i the insert or update is is performed -- this occurs if autoEdit is TRUE + \i the insert or update is discarded -- this occurs if autoEdit is FALSE + \endlist +*/ + +void QDataBrowser::setAutoEdit( bool autoEdit ) +{ + d->dat.setAutoEdit( autoEdit ); +} + +bool QDataBrowser::autoEdit() const +{ + return d->dat.autoEdit(); +} + +/*! + \fn void QDataBrowser::firstRecordAvailable( bool available ) + + This signal is emitted whenever the position of the cursor + changes. The \a available parameter indicates whether or not the + first record in the default cursor is available. +*/ + +/*! + \fn void QDataBrowser::lastRecordAvailable( bool available ) + + This signal is emitted whenever the position of the cursor + changes. The \a available parameter indicates whether or not the + last record in the default cursor is available. +*/ + +/*! + \fn void QDataBrowser::nextRecordAvailable( bool available ) + + This signal is emitted whenever the position of the cursor + changes. The \a available parameter indicates whether or not the + next record in the default cursor is available. +*/ + + +/*! + \fn void QDataBrowser::prevRecordAvailable( bool available ) + + This signal is emitted whenever the position of the cursor + changes. The \a available parameter indicates whether or not the + previous record in the default cursor is available. +*/ + + +/*! + \fn void QDataBrowser::currentChanged( const QSqlRecord* record ) + + This signal is emitted whenever the current cursor position + changes. The \a record parameter points to the contents of the + current cursor's record. +*/ + + +/*! + \fn void QDataBrowser::primeInsert( QSqlRecord* buf ) + + This signal is emitted when the data browser enters insertion + mode. The \a buf parameter points to the record buffer that is to + be inserted. Connect to this signal to, for example, prime the + record buffer with default data values, auto-numbered fields etc. + (Note that QSqlCursor::primeInsert() is \e not called on the + default cursor, as this would corrupt values in the form.) + + \sa insert() +*/ + + +/*! + \fn void QDataBrowser::primeUpdate( QSqlRecord* buf ) + + This signal is emitted when the data browser enters update mode. + Note that during navigation (first(), last(), next(), prev()), + each record that is shown in the default form is primed for + update. The \a buf parameter points to the record buffer being + updated. (Note that QSqlCursor::primeUpdate() is \e not called on + the default cursor, as this would corrupt values in the form.) + Connect to this signal in order to, for example, keep track of + which records have been updated, perhaps for auditing purposes. + + \sa update() +*/ + +/*! + \fn void QDataBrowser::primeDelete( QSqlRecord* buf ) + + This signal is emitted when the data browser enters deletion mode. + The \a buf parameter points to the record buffer being deleted. + (Note that QSqlCursor::primeDelete() is \e not called on the + default cursor, as this would corrupt values in the form.) + Connect to this signal in order to, for example, save a copy of + the deleted record for auditing purposes. + + \sa del() +*/ + + +/*! + \fn void QDataBrowser::cursorChanged( QSqlCursor::Mode mode ) + + This signal is emitted whenever the cursor record was changed due + to navigation. The \a mode parameter is the edit that just took + place, e.g. Insert, Update or Delete. See \l QSqlCursor::Mode. +*/ + + +/*! + Refreshes the data browser's data using the default cursor. The + browser's current filter and sort are applied if they have been + set. + + \sa setFilter() setSort() +*/ + +void QDataBrowser::refresh() +{ + d->cur.refresh(); +} + + +/*! + Performs an insert operation on the data browser's cursor. If + there is no default cursor or no default form, nothing happens. + + If auto-editing is on (see setAutoEdit()), the following happens: + + \list + \i If the browser is already actively inserting a record, + the current form's data is inserted into the database. + \i If the browser is not inserting a record, but the current record + was changed by the user, the record is updated in the database with + the current form's data (i.e. with the changes). + \endlist + + If there is an error handling any of the above auto-edit actions, + handleError() is called and no insert or update is performed. + + If no error occurred, or auto-editing is not enabled, the data browser + begins actively inserting a record into the database by performing the + following actions: + + \list + \i The default cursor is primed for insert using QSqlCursor::primeInsert(). + \i The primeInsert() signal is emitted. + \i The form is updated with the values in the default cursor's. + edit buffer so that the user can fill in the values to be inserted. + \endlist + +*/ + +void QDataBrowser::insert() +{ + QSqlRecord* buf = d->frm.record(); + QSqlCursor* cur = d->cur.cursor(); + if ( !buf || !cur ) + return; + bool doIns = TRUE; + QSql::Confirm conf = QSql::Yes; + switch ( d->dat.mode() ) { + case QSql::Insert: + if ( autoEdit() ) { + if ( confirmInsert() ) + conf = confirmEdit( QSql::Insert ); + switch ( conf ) { + case QSql::Yes: + insertCurrent(); + break; + case QSql::No: + break; + case QSql::Cancel: + doIns = FALSE; + break; + } + } + break; + default: + if ( autoEdit() && currentEdited() ) { + if ( confirmUpdate() ) + conf = confirmEdit( QSql::Update ); + switch ( conf ) { + case QSql::Yes: + updateCurrent(); + break; + case QSql::No: + break; + case QSql::Cancel: + doIns = FALSE; + break; + } + } + break; + } + if ( doIns ) { + d->dat.setMode( QSql::Insert ); + sqlCursor()->primeInsert(); + emit primeInsert( d->frm.record() ); + readFields(); + } +} + + +/*! + Performs an update operation on the data browser's cursor. + + If there is no default cursor or no default form, nothing happens. + Otherwise, the following happens: + + If the data browser is actively inserting a record (see insert()), + that record is inserted into the database using insertCurrent(). + Otherwise, the database is updated with the current form's data + using updateCurrent(). If there is an error handling either + action, handleError() is called. +*/ + +void QDataBrowser::update() +{ + QSqlRecord* buf = d->frm.record(); + QSqlCursor* cur = d->cur.cursor(); + if ( !buf || !cur ) + return; + QSql::Confirm conf = QSql::Yes; + switch ( d->dat.mode() ){ + case QSql::Insert: + if ( confirmInsert() ) + conf = confirmEdit( QSql::Insert ); + switch ( conf ) { + case QSql::Yes: + if ( insertCurrent() ) + d->dat.setMode( QSql::Update ); + break; + case QSql::No: + d->dat.setMode( QSql::Update ); + cur->editBuffer( TRUE ); + readFields(); + break; + case QSql::Cancel: + break; + } + break; + default: + d->dat.setMode( QSql::Update ); + if ( confirmUpdate() ) + conf = confirmEdit( QSql::Update ); + switch ( conf ) { + case QSql::Yes: + updateCurrent(); + break; + case QSql::No: + case QSql::Cancel: + break; + } + break; + } +} + + +/*! + Performs a delete operation on the data browser's cursor. If there + is no default cursor or no default form, nothing happens. + + Otherwise, the following happens: + + The current form's record is deleted from the database, providing + that the data browser is not in insert mode. If the data browser + is actively inserting a record (see insert()), the insert action + is canceled, and the browser navigates to the last valid record + that was current. If there is an error, handleError() is called. +*/ + +void QDataBrowser::del() +{ + QSqlRecord* buf = d->frm.record(); + QSqlCursor* cur = d->cur.cursor(); + if ( !buf || !cur ) + return; + QSql::Confirm conf = QSql::Yes; + switch ( d->dat.mode() ){ + case QSql::Insert: + if ( confirmCancels() ) + conf = confirmCancel( QSql::Insert ); + if ( conf == QSql::Yes ) { + cur->editBuffer( TRUE ); /* restore from cursor */ + readFields(); + d->dat.setMode( QSql::Update ); + } else + d->dat.setMode( QSql::Insert ); + break; + default: + if ( confirmDelete() ) + conf = confirmEdit( QSql::Delete ); + switch ( conf ) { + case QSql::Yes: + emit primeDelete( buf ); + deleteCurrent(); + break; + case QSql::No: + case QSql::Cancel: + break; + } + d->dat.setMode( QSql::Update ); + break; + } +} + +/*! + Moves the default cursor to the record specified by the index \a i + and refreshes the default form to display this record. If there is + no default form or no default cursor, nothing happens. If \a + relative is TRUE (the default is FALSE), the cursor is moved + relative to its current position. If the data browser successfully + navigated to the desired record, the default cursor is primed for + update and the primeUpdate() signal is emitted. + + If the browser is already positioned on the desired record nothing + happens. +*/ + +bool QDataBrowser::seek( int i, bool relative ) +{ + int b = 0; + QSqlCursor* cur = d->cur.cursor(); + if ( !cur ) + return FALSE; + if ( preNav() ) + b = cur->seek( i, relative ); + postNav( b ); + return b; +} + +/*! + Moves the default cursor to the first record and refreshes the + default form to display this record. If there is no default form + or no default cursor, nothing happens. If the data browser + successfully navigated to the first record, the default cursor is + primed for update and the primeUpdate() signal is emitted. + + If the browser is already positioned on the first record nothing + happens. + +*/ + +void QDataBrowser::first() +{ + nav( &QSqlCursor::first ); +} + + +/*! + Moves the default cursor to the last record and refreshes the + default form to display this record. If there is no default form + or no default cursor, nothing happens. If the data browser + successfully navigated to the last record, the default cursor is + primed for update and the primeUpdate() signal is emitted. + + If the browser is already positioned on the last record nothing + happens. +*/ + +void QDataBrowser::last() +{ + nav( &QSqlCursor::last ); +} + + +/*! + Moves the default cursor to the next record and refreshes the + default form to display this record. If there is no default form + or no default cursor, nothing happens. If the data browser + successfully navigated to the next record, the default cursor is + primed for update and the primeUpdate() signal is emitted. + + If the browser is positioned on the last record nothing happens. +*/ + +void QDataBrowser::next() +{ + nav( &QSqlCursor::next ); +} + + +/*! + Moves the default cursor to the previous record and refreshes the + default form to display this record. If there is no default form + or no default cursor, nothing happens. If the data browser + successfully navigated to the previous record, the default cursor + is primed for update and the primeUpdate() signal is emitted. + + If the browser is positioned on the first record nothing happens. +*/ + +void QDataBrowser::prev() +{ + nav( &QSqlCursor::prev ); +} + +/*! + Reads the fields from the default cursor's edit buffer and + displays them in the form. If there is no default cursor or no + default form, nothing happens. +*/ + +void QDataBrowser::readFields() +{ + d->frm.readFields(); +} + + +/*! + Writes the form's data to the default cursor's edit buffer. If + there is no default cursor or no default form, nothing happens. +*/ + +void QDataBrowser::writeFields() +{ + d->frm.writeFields(); +} + + +/*! + Clears all the values in the form. + + All the edit buffer field values are set to their 'zero state', + e.g. 0 for numeric fields and "" for string fields. Then the + widgets are updated using the property map. For example, a + combobox that is property-mapped to integers would scroll to the + first item. See the \l QSqlPropertyMap constructor for the default + mappings of widgets to properties. +*/ + +void QDataBrowser::clearValues() +{ + d->frm.clearValues(); +} + +/*! + Reads the fields from the default form into the default cursor and + performs an insert on the default cursor. If there is no default + form or no default cursor, nothing happens. If an error occurred + during the insert into the database, handleError() is called and + FALSE is returned. If the insert was successfull, the cursor is + refreshed and relocated to the newly inserted record, the + cursorChanged() signal is emitted, and TRUE is returned. + + \sa cursorChanged() sqlCursor() form() handleError() +*/ + +bool QDataBrowser::insertCurrent() +{ + if ( isReadOnly() ) + return FALSE; + QSqlRecord* buf = d->frm.record(); + QSqlCursor* cur = d->cur.cursor(); + if ( !buf || !cur ) + return FALSE; + writeFields(); + emit beforeInsert( buf ); + int ar = cur->insert(); + if ( !ar || !cur->isActive() ) { + handleError( cur->lastError() ); + refresh(); + updateBoundary(); + } else { + refresh(); + d->cur.findBuffer( cur->primaryIndex() ); + updateBoundary(); + cursorChanged( QSqlCursor::Insert ); + return TRUE; + } + return FALSE; +} + + +/*! + Reads the fields from the default form into the default cursor and + performs an update on the default cursor. If there is no default + form or no default cursor, nothing happens. If an error occurred + during the update on the database, handleError() is called and + FALSE is returned. If the update was successfull, the cursor is + refreshed and relocated to the updated record, the cursorChanged() + signal is emitted, and TRUE is returned. + + \sa cursor() form() handleError() +*/ + +bool QDataBrowser::updateCurrent() +{ + if ( isReadOnly() ) + return FALSE; + QSqlRecord* buf = d->frm.record(); + QSqlCursor* cur = d->cur.cursor(); + if ( !buf || !cur ) + return FALSE; + writeFields(); + emit beforeUpdate( buf ); + int ar = cur->update(); + if ( !ar || !cur->isActive() ) { + handleError( cur->lastError() ); + refresh(); + updateBoundary(); + } else { + refresh(); + d->cur.findBuffer( cur->primaryIndex() ); + updateBoundary(); + cur->editBuffer( TRUE ); + cursorChanged( QSqlCursor::Update ); + readFields(); + return TRUE; + } + return FALSE; +} + + +/*! + Performs a delete on the default cursor using the values from the + default form and updates the default form. If there is no default + form or no default cursor, nothing happens. If the deletion was + successful, the cursor is repositioned to the nearest record and + TRUE is returned. The nearest record is the next record if there + is one otherwise the previous record if there is one. If an error + occurred during the deletion from the database, handleError() is + called and FALSE is returned. + + \sa cursor() form() handleError() +*/ + +bool QDataBrowser::deleteCurrent() +{ + if ( isReadOnly() ) + return FALSE; + QSqlRecord* buf = d->frm.record(); + QSqlCursor* cur = d->cur.cursor(); + if ( !buf || !cur ) + return FALSE; + writeFields(); + int n = cur->at(); + emit beforeDelete( buf ); + int ar = cur->del(); + if ( ar ) { + refresh(); + updateBoundary(); + cursorChanged( QSqlCursor::Delete ); + if ( !cur->seek( n ) ) + last(); + if ( cur->isValid() ) { + cur->editBuffer( TRUE ); + readFields(); + } else { + clearValues(); + } + return TRUE; + } else { + if ( !cur->isActive() ) { + handleError( cur->lastError() ); + refresh(); + updateBoundary(); + } + } + return FALSE; +} + + +/*! + Returns TRUE if the form's edit buffer differs from the current + cursor buffer; otherwise returns FALSE. +*/ + +bool QDataBrowser::currentEdited() +{ + QSqlRecord* buf = d->frm.record(); + QSqlCursor* cur = d->cur.cursor(); + if ( !buf || !cur ) + return FALSE; + if ( !cur->isActive() || !cur->isValid() ) + return FALSE; + writeFields(); + for ( uint i = 0; i < cur->count(); ++i ) { + if ( cur->value(i) != buf->value(i) ) + return TRUE; + } + return FALSE; +} + +/*! \internal + + Pre-navigation checking. +*/ + +bool QDataBrowser::preNav() +{ + QSqlRecord* buf = d->frm.record(); + QSqlCursor* cur = d->cur.cursor(); + if ( !buf || !cur ) + return FALSE; + + if ( !isReadOnly() && autoEdit() && currentEdited() ) { + bool ok = TRUE; + QSql::Confirm conf = QSql::Yes; + switch ( d->dat.mode() ){ + case QSql::Insert: + if ( confirmInsert() ) + conf = confirmEdit( QSql::Insert ); + switch ( conf ) { + case QSql::Yes: + ok = insertCurrent(); + d->dat.setMode( QSql::Update ); + break; + case QSql::No: + d->dat.setMode( QSql::Update ); + break; + case QSql::Cancel: + return FALSE; + } + break; + default: + if ( confirmUpdate() ) + conf = confirmEdit( QSql::Update ); + switch ( conf ) { + case QSql::Yes: + ok = updateCurrent(); + break; + case QSql::No: + break; + case QSql::Cancel: + return FALSE; + } + } + return ok; + } + return TRUE; +} + +/*! \internal + + Handles post-navigation according to \a primeUpd. +*/ + +void QDataBrowser::postNav( bool primeUpd ) +{ + if ( primeUpd ) { + QSqlRecord* buf = d->frm.record(); + QSqlCursor* cur = d->cur.cursor(); + if ( !buf || !cur ) + return; + currentChanged( cur ); + cur->primeUpdate(); + emit primeUpdate( buf ); + readFields(); + } + updateBoundary(); +} + +/*! \internal + + Navigate default cursor according to \a nav. Handles autoEdit. + +*/ +void QDataBrowser::nav( Nav nav ) +{ + int b = 0; + QSqlCursor* cur = d->cur.cursor(); + if ( !cur ) + return; + if ( preNav() ) + b = (cur->*nav)(); + postNav( b ); +} + +/*! + If boundaryChecking() is TRUE, checks the boundary of the current + default cursor and emits signals which indicate the position of + the cursor. +*/ + +void QDataBrowser::updateBoundary() +{ + if ( d->boundaryCheck ) { + Boundary bound = boundary(); + switch ( bound ) { + case Unknown: + case None: + emit firstRecordAvailable( TRUE ); + emit prevRecordAvailable( TRUE ); + emit nextRecordAvailable( TRUE ); + emit lastRecordAvailable( TRUE ); + break; + + case BeforeBeginning: + emit firstRecordAvailable( FALSE ); + emit prevRecordAvailable( FALSE ); + emit nextRecordAvailable( TRUE ); + emit lastRecordAvailable( TRUE ); + break; + + case Beginning: + emit firstRecordAvailable( FALSE ); + emit prevRecordAvailable( FALSE ); + emit nextRecordAvailable( TRUE ); + emit lastRecordAvailable( TRUE ); + break; + + case End: + emit firstRecordAvailable( TRUE ); + emit prevRecordAvailable( TRUE ); + emit nextRecordAvailable( FALSE ); + emit lastRecordAvailable( FALSE ); + break; + + case AfterEnd: + emit firstRecordAvailable( TRUE ); + emit prevRecordAvailable( TRUE ); + emit nextRecordAvailable( FALSE ); + emit lastRecordAvailable( FALSE ); + break; + } + } +} + +/*! + Virtual function which handles the error \a error. The default + implementation warns the user with a message box. +*/ + +void QDataBrowser::handleError( const QSqlError& error ) +{ + d->dat.handleError( this, error ); +} + +/*! + Protected virtual function which returns a confirmation for an + edit of mode \a m. Derived classes can reimplement this function + and provide their own confirmation dialog. The default + implementation uses a message box which prompts the user to + confirm the edit action. +*/ + +QSql::Confirm QDataBrowser::confirmEdit( QSql::Op m ) +{ + return d->dat.confirmEdit( this, m ); +} + +/*! + Protected virtual function which returns a confirmation for + cancelling an edit mode \a m. Derived classes can reimplement this + function and provide their own confirmation dialog. The default + implementation uses a message box which prompts the user to + confirm the edit action. +*/ + +QSql::Confirm QDataBrowser::confirmCancel( QSql::Op m ) +{ + return d->dat.confirmCancel( this, m ); +} + +/*! + \fn void QDataBrowser::beforeInsert( QSqlRecord* buf ) + + This signal is emitted just before the cursor's edit buffer is + inserted into the database. The \a buf parameter points to the + edit buffer being inserted. You might connect to this signal to + populate a generated primary key for example. +*/ + +/*! + \fn void QDataBrowser::beforeUpdate( QSqlRecord* buf ) + + This signal is emitted just before the cursor's edit buffer is + updated in the database. The \a buf parameter points to the edit + buffer being updated. You might connect to this signal to capture + some auditing information about the update. +*/ + +/*! + \fn void QDataBrowser::beforeDelete( QSqlRecord* buf ) + + This signal is emitted just before the cursor's edit buffer is + deleted from the database. The \a buf parameter points to the edit + buffer being deleted. You might connect to this signal to capture + some auditing information about the deletion. +*/ + +#endif diff --git a/main/dependencies/qt3/src/sql/qdatabrowser.h b/main/dependencies/qt3/src/sql/qdatabrowser.h new file mode 100644 index 000000000..d2db1fa15 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qdatabrowser.h @@ -0,0 +1,177 @@ +/**************************************************************************** +** +** Definition of QDataBrowser class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QDATABROWSER_H +#define QDATABROWSER_H + +#ifndef QT_H +#include "qwidget.h" +#include "qstring.h" +#include "qstringlist.h" +#include "qsql.h" +#include "qsqlindex.h" +#include "qsqlcursor.h" +#include "qsqlerror.h" +#endif // QT_H + +#ifndef QT_NO_SQL_VIEW_WIDGETS + +class QSqlForm; +class QDataBrowserPrivate; + +class Q_EXPORT QDataBrowser : public QWidget +{ + Q_OBJECT + Q_PROPERTY( bool boundaryChecking READ boundaryChecking WRITE setBoundaryChecking ) + Q_PROPERTY( QString filter READ filter WRITE setFilter ) + Q_PROPERTY( QStringList sort READ sort WRITE setSort ) + Q_PROPERTY( bool confirmEdits READ confirmEdits WRITE setConfirmEdits ) + Q_PROPERTY( bool confirmInsert READ confirmInsert WRITE setConfirmInsert ) + Q_PROPERTY( bool confirmUpdate READ confirmUpdate WRITE setConfirmUpdate ) + Q_PROPERTY( bool confirmDelete READ confirmDelete WRITE setConfirmDelete ) + Q_PROPERTY( bool confirmCancels READ confirmCancels WRITE setConfirmCancels ) + Q_PROPERTY( bool readOnly READ isReadOnly WRITE setReadOnly ) + Q_PROPERTY( bool autoEdit READ autoEdit WRITE setAutoEdit ) + +public: + QDataBrowser( QWidget* parent=0, const char* name=0, WFlags fl = 0 ); + ~QDataBrowser(); + + enum Boundary { + Unknown, + None, + BeforeBeginning, + Beginning, + End, + AfterEnd + }; + + Boundary boundary(); + void setBoundaryChecking( bool active ); + bool boundaryChecking() const; + + void setSort( const QSqlIndex& sort ); + void setSort( const QStringList& sort ); + QStringList sort() const; + void setFilter( const QString& filter ); + QString filter() const; + virtual void setSqlCursor( QSqlCursor* cursor, bool autoDelete = FALSE ); + QSqlCursor* sqlCursor() const; + virtual void setForm( QSqlForm* form ); + QSqlForm* form(); + + virtual void setConfirmEdits( bool confirm ); + virtual void setConfirmInsert( bool confirm ); + virtual void setConfirmUpdate( bool confirm ); + virtual void setConfirmDelete( bool confirm ); + virtual void setConfirmCancels( bool confirm ); + bool confirmEdits() const; + bool confirmInsert() const; + bool confirmUpdate() const; + bool confirmDelete() const; + bool confirmCancels() const; + + virtual void setReadOnly( bool active ); + bool isReadOnly() const; + virtual void setAutoEdit( bool autoEdit ); + bool autoEdit() const; + + virtual bool seek( int i, bool relative = FALSE ); + +signals: + void firstRecordAvailable( bool available ); + void lastRecordAvailable( bool available ); + void nextRecordAvailable( bool available ); + void prevRecordAvailable( bool available ); + + void currentChanged( const QSqlRecord* record ); + void primeInsert( QSqlRecord* buf ); + void primeUpdate( QSqlRecord* buf ); + void primeDelete( QSqlRecord* buf ); + void beforeInsert( QSqlRecord* buf ); + void beforeUpdate( QSqlRecord* buf ); + void beforeDelete( QSqlRecord* buf ); + void cursorChanged( QSqlCursor::Mode mode ); + +public slots: + virtual void refresh(); + + virtual void insert(); + virtual void update(); + virtual void del(); + + virtual void first(); + virtual void last(); + virtual void next(); + virtual void prev(); + + virtual void readFields(); + virtual void writeFields(); + virtual void clearValues(); + + void updateBoundary(); + +protected: + virtual bool insertCurrent(); + virtual bool updateCurrent(); + virtual bool deleteCurrent(); + virtual bool currentEdited(); + + virtual QSql::Confirm confirmEdit( QSql::Op m ); + virtual QSql::Confirm confirmCancel( QSql::Op m ); + + virtual void handleError( const QSqlError& error ); + +private: + typedef bool (QSqlCursor::*Nav)(); + bool preNav(); + void postNav( bool primeUpd ); + void nav( Nav nav ); + QDataBrowserPrivate* d; + +#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator= + QDataBrowser( const QDataBrowser & ); + QDataBrowser &operator=( const QDataBrowser & ); +#endif +}; + + +#endif +#endif diff --git a/main/dependencies/qt3/src/sql/qdatatable.cpp b/main/dependencies/qt3/src/sql/qdatatable.cpp new file mode 100644 index 000000000..d1404d9ba --- /dev/null +++ b/main/dependencies/qt3/src/sql/qdatatable.cpp @@ -0,0 +1,2322 @@ +/**************************************************************************** +** +** Implementation of QDataTable class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qdatatable.h" + +#ifndef QT_NO_SQL_VIEW_WIDGETS + +#include "qsqldriver.h" +#include "qsqleditorfactory.h" +#include "qsqlpropertymap.h" +#include "qapplication.h" +#include "qlayout.h" +#include "qpainter.h" +#include "qpopupmenu.h" +#include "qvaluelist.h" +#include "qsqlmanager_p.h" +#include "qdatetime.h" +#include "qcursor.h" +#include "qtimer.h" + +//#define QT_DEBUG_DATATABLE + +class QDataTablePrivate +{ +public: + QDataTablePrivate() + : nullTxtChanged( FALSE ), + haveAllRows( FALSE ), + continuousEdit( FALSE ), + editorFactory( 0 ), + propertyMap( 0 ), + editRow( -1 ), + editCol( -1 ), + insertRowLast( -1 ), + insertPreRows( -1 ), + editBuffer( 0 ), + cancelMode( FALSE ), + cancelInsert( FALSE ), + cancelUpdate( FALSE ) + {} + ~QDataTablePrivate() { if ( propertyMap ) delete propertyMap; } + + QString nullTxt; + bool nullTxtChanged; + typedef QValueList< uint > ColIndex; + ColIndex colIndex; + bool haveAllRows; + bool continuousEdit; + QSqlEditorFactory* editorFactory; + QSqlPropertyMap* propertyMap; + QString trueTxt; + Qt::DateFormat datefmt; + QString falseTxt; + int editRow; + int editCol; + int insertRowLast; + QString insertHeaderLabelLast; + int insertPreRows; + QSqlRecord* editBuffer; + bool cancelMode; + bool cancelInsert; + bool cancelUpdate; + int lastAt; + QString ftr; + QStringList srt; + QStringList fld; + QStringList fldLabel; + QValueList<int> fldWidth; + QValueList<QIconSet> fldIcon; + QValueList<bool> fldHidden; + QSqlCursorManager cur; + QDataManager dat; +}; + +#ifdef QT_DEBUG_DATATABLE +void qt_debug_buffer( const QString& msg, QSqlRecord* cursor ) +{ + qDebug("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + qDebug(msg); + for ( uint j = 0; j < cursor->count(); ++j ) { + qDebug(cursor->field(j)->name() + " type:" + QString(cursor->field(j)->value().typeName()) + " value:" + cursor->field(j)->value().toString() ); + } +} +#endif + +/*! + \enum QDataTable::Refresh + + This enum describes the refresh options. + + \value RefreshData refresh the data, i.e. read it from the database + \value RefreshColumns refresh the list of fields, e.g. the column headings + \value RefreshAll refresh both the data and the list of fields +*/ + + +/*! + \class QDataTable qdatatable.h + \brief The QDataTable class provides a flexible SQL table widget that supports browsing and editing. + + \ingroup database + \mainclass + \module sql + + QDataTable supports various functions for presenting and editing + SQL data from a \l QSqlCursor in a table. + + If you want a to present your data in a form use QDataBrowser, or + for read-only forms, QDataView. + + When displaying data, QDataTable only retrieves data for visible + rows. If the driver supports the 'query size' property the + QDataTable will have the correct number of rows and the vertical + scrollbar will accurately reflect the number of rows displayed in + proportion to the number of rows in the dataset. If the driver + does not support the 'query size' property, rows are dynamically + fetched from the database on an as-needed basis with the scrollbar + becoming more accurate as the user scrolls down through the + records. This allows extremely large queries to be displayed as + quickly as possible, with minimum memory usage. + + QDataTable inherits QTable's API and extends it with functions to + sort and filter the data and sort columns. See setSqlCursor(), + setFilter(), setSort(), setSorting(), sortColumn() and refresh(). + + When displaying editable cursors, cell editing will be enabled. + (For more information on editable cursors, see \l QSqlCursor). + QDataTable can be used to modify existing data and to add new + records. When a user makes changes to a field in the table, the + cursor's edit buffer is used. The table will not send changes in + the edit buffer to the database until the user moves to a + different record in the grid or presses Enter. Cell editing is + initiated by pressing F2 (or right clicking and then clicking the + appropriate popup menu item) and canceled by pressing Esc. If + there is a problem updating or adding data, errors are handled + automatically (see handleError() to change this behavior). Note + that if autoEdit() is FALSE navigating to another record will + cancel the insert or update. + + The user can be asked to confirm all edits with setConfirmEdits(). + For more precise control use setConfirmInsert(), + setConfirmUpdate(), setConfirmDelete() and setConfirmCancels(). + Use setAutoEdit() to control the behaviour of the table when the + user edits a record and then navigates. (Note that setAutoDelete() + is unrelated; it is used to set whether the QSqlCursor is deleted + when the table is deleted.) + + Since the data table can perform edits, it must be able to + uniquely identify every record so that edits are correctly + applied. Because of this the underlying cursor must have a valid + primary index to ensure that a unique record is inserted, updated + or deleted within the database otherwise the database may be + changed to an inconsistent state. + + QDataTable creates editors using the default \l QSqlEditorFactory. + Different editor factories can be used by calling + installEditorFactory(). A property map is used to map between the + cell's value and the editor. You can use your own property map + with installPropertyMap(). + + The contents of a cell is available as a QString with text() or as + a QVariant with value(). The current record is returned by + currentRecord(). Use the find() function to search for a string in + the table. + + Editing actions can be applied programatically. For example, the + insertCurrent() function reads the fields from the current record + into the cursor and performs the insert. The updateCurrent() and + deleteCurrent() functions perform similarly to update and delete + the current record respectively. + + Columns in the table can be created automatically based on the + cursor (see setSqlCursor()). Columns can be manipulated manually + using addColumn(), removeColumn() and setColumn(). + + The table automatically copies many of the properties of the + cursor to format the display of data within cells (alignment, + visibility, etc.). The cursor can be changed with setSqlCursor(). + The filter (see setFilter()) and sort defined within the table are + used instead of the filter and sort set on the cursor. For sorting + options see setSort(), sortColumn(), sortAscending() and + sortDescending(). Note that sorting operations will not behave as + expected if you are using a QSqlSelectCursor because it uses + user-defined SQL queries to obtain data. + + The text used to represent NULL, TRUE and FALSE values can be + changed with setNullText(), setTrueText() and setFalseText() + respectively. You can change the appearance of cells by + reimplementing paintField(). + + Whenever a new row is selected in the table the currentChanged() + signal is emitted. The primeInsert() signal is emitted when an + insert is initiated. The primeUpdate() and primeDelete() signals + are emitted when update and deletion are initiated respectively. + Just before the database is updated a signal is emitted; + beforeInsert(), beforeUpdate() or beforeDelete() as appropriate. + +*/ + +/*! + Constructs a data table which is a child of \a parent, called + name \a name. +*/ + +QDataTable::QDataTable ( QWidget * parent, const char * name ) + : QTable( parent, name ) +{ + init(); +} + +/*! + Constructs a data table which is a child of \a parent, called name + \a name using the cursor \a cursor. + + If \a autoPopulate is TRUE (the default is FALSE), columns are + automatically created based upon the fields in the \a cursor + record. Note that \a autoPopulate only governs the creation of + columns; to load the cursor's data into the table use refresh(). + + If the \a cursor is read-only, the table also becomes read-only. + In addition, the table adopts the cursor's driver's definition for + representing NULL values as strings. +*/ + +QDataTable::QDataTable ( QSqlCursor* cursor, bool autoPopulate, QWidget * parent, const char * name ) + : QTable( parent, name ) +{ + init(); + setSqlCursor( cursor, autoPopulate ); +} + +/*! \internal +*/ + + +void QDataTable::init() +{ + d = new QDataTablePrivate(); + setAutoEdit( TRUE ); + setSelectionMode( SingleRow ); + setFocusStyle( FollowStyle ); + d->trueTxt = tr( "True" ); + d->falseTxt = tr( "False" ); + d->datefmt = Qt::LocalDate; + reset(); + connect( this, SIGNAL( selectionChanged() ), + SLOT( updateCurrentSelection())); +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QDataTable::~QDataTable() +{ + delete d; +} + + +/*! + Adds the next column to be displayed using the field \a fieldName, + column label \a label, width \a width and iconset \a iconset. + + If \a label is specified, it is used as the column's header label, + otherwise the field's display label is used when setSqlCursor() is + called. The \a iconset is used to set the icon used by the column + header; by default there is no icon. + + \sa setSqlCursor() refresh() +*/ + +void QDataTable::addColumn( const QString& fieldName, + const QString& label, + int width, + const QIconSet& iconset ) +{ + d->fld += fieldName; + d->fldLabel += label; + d->fldIcon += iconset; + d->fldWidth += width; + d->fldHidden += FALSE; +} + +/*! + Sets the \a col column to display using the field \a fieldName, + column label \a label, width \a width and iconset \a iconset. + + If \a label is specified, it is used as the column's header label, + otherwise the field's display label is used when setSqlCursor() is + called. The \a iconset is used to set the icon used by the column + header; by default there is no icon. + + \sa setSqlCursor() refresh() +*/ + +void QDataTable::setColumn( uint col, const QString& fieldName, + const QString& label, + int width, + const QIconSet& iconset ) +{ + d->fld[col]= fieldName; + d->fldLabel[col] = label; + d->fldIcon[col] = iconset; + d->fldWidth[col] = width; + d->fldHidden[col] = FALSE; +} + +/*! + Removes column \a col from the list of columns to be displayed. If + \a col does not exist, nothing happens. + + \sa QSqlField +*/ + +void QDataTable::removeColumn( uint col ) +{ + if ( d->fld.at( col ) != d->fld.end() ) { + d->fld.remove( d->fld.at( col ) ); + d->fldLabel.remove( d->fldLabel.at( col ) ); + d->fldIcon.remove( d->fldIcon.at( col ) ); + d->fldWidth.remove( d->fldWidth.at( col ) ); + d->fldHidden.remove( d->fldHidden.at( col ) ); + } +} + +/*! + Sets the column \a col to the width \a w. Note that unlike QTable + the QDataTable is not immediately redrawn, you must call + refresh(QDataTable::RefreshColumns) + yourself. + + \sa refresh() +*/ +void QDataTable::setColumnWidth( int col, int w ) +{ + if ( d->fldWidth.at( col ) != d->fldWidth.end() ) { + d->fldWidth[col] = w; + } +} + +/*! + Resizes column \a col so that the column width is wide enough to + display the widest item the column contains (including the column + label). If the table's QSqlCursor is not currently active, the + cursor will be refreshed before the column width is calculated. Be + aware that this function may be slow on tables that contain large + result sets. +*/ +void QDataTable::adjustColumn( int col ) +{ + QSqlCursor * cur = sqlCursor(); + if ( !cur || cur->count() <= (uint)col ) + return; + if ( !cur->isActive() ) { + d->cur.refresh(); + } + int oldRow = currentRow(); + int w = fontMetrics().width( horizontalHeader()->label( col ) + "W" ); + cur->seek( QSql::BeforeFirst ); + while ( cur->next() ) { + w = QMAX( w, fontMetrics().width( fieldToString( cur->field( indexOf( col ) ) ) ) + 10 ); + } + setColumnWidth( col, w ); + cur->seek( oldRow ); + refresh( RefreshColumns ); +} + +/*! \reimp +*/ +void QDataTable::setColumnStretchable( int col, bool s ) +{ + if ( numCols() == 0 ) { + refresh( RefreshColumns ); + } + if ( numCols() > col ) { + QTable::setColumnStretchable( col, s ); + } +} + +QString QDataTable::filter() const +{ + return d->cur.filter(); +} + +/*! + \property QDataTable::filter + \brief the data filter for the data table + + The filter applies to the data shown in the table. To view data + with a new filter, use refresh(). A filter string is an SQL WHERE + clause without the WHERE keyword. + + There is no default filter. + + \sa sort() + +*/ + +void QDataTable::setFilter( const QString& filter ) +{ + d->cur.setFilter( filter ); +} + + +/*! + \property QDataTable::sort + \brief the data table's sort + + The table's sort affects the order in which data records are + displayed in the table. To apply a sort, use refresh(). + + When examining the sort property, a string list is returned with + each item having the form 'fieldname order' (e.g., 'id ASC', + 'surname DESC'). + + There is no default sort. + + Note that if you want to iterate over the sort list, you should + iterate over a copy, e.g. + \code + QStringList list = myDataTable.sort(); + QStringList::Iterator it = list.begin(); + while( it != list.end() ) { + myProcessing( *it ); + ++it; + } + \endcode + + \sa filter() refresh() +*/ + +void QDataTable::setSort( const QStringList& sort ) +{ + d->cur.setSort( sort ); +} + +/*! + \overload + + Sets the sort to be applied to the displayed data to \a sort. If + there is no current cursor, nothing happens. A QSqlIndex contains + field names and their ordering (ASC or DESC); these are used to + compose the ORDER BY clause. + + \sa sort() +*/ + +void QDataTable::setSort( const QSqlIndex& sort ) +{ + d->cur.setSort( sort ); +} + +QStringList QDataTable::sort() const +{ + return d->cur.sort(); +} + +/*! + Returns the cursor used by the data table. +*/ + +QSqlCursor* QDataTable::sqlCursor() const +{ + return d->cur.cursor(); +} + +void QDataTable::setConfirmEdits( bool confirm ) +{ + d->dat.setConfirmEdits( confirm ); +} + +void QDataTable::setConfirmInsert( bool confirm ) +{ + d->dat.setConfirmInsert( confirm ); +} + +void QDataTable::setConfirmUpdate( bool confirm ) +{ + d->dat.setConfirmUpdate( confirm ); +} + +void QDataTable::setConfirmDelete( bool confirm ) +{ + d->dat.setConfirmDelete( confirm ); +} + +/*! + \property QDataTable::confirmEdits + \brief whether the data table confirms edit operations + + If the confirmEdits property is TRUE, the data table confirms all + edit operations (inserts, updates and deletes). Finer control of + edit confirmation can be achieved using \l confirmCancels, \l + confirmInsert, \l confirmUpdate and \l confirmDelete. + + \sa confirmCancels() confirmInsert() confirmUpdate() confirmDelete() +*/ + +bool QDataTable::confirmEdits() const +{ + return ( d->dat.confirmEdits() ); +} + +/*! + \property QDataTable::confirmInsert + \brief whether the data table confirms insert operations + + If the confirmInsert property is TRUE, all insertions must be + confirmed by the user through a message box (this behaviour can be + changed by overriding the confirmEdit() function), otherwise all + insert operations occur immediately. + + \sa confirmCancels() confirmEdits() confirmUpdate() confirmDelete() +*/ + +bool QDataTable::confirmInsert() const +{ + return ( d->dat.confirmInsert() ); +} + +/*! + \property QDataTable::confirmUpdate + \brief whether the data table confirms update operations + + If the confirmUpdate property is TRUE, all updates must be + confirmed by the user through a message box (this behaviour can be + changed by overriding the confirmEdit() function), otherwise all + update operations occur immediately. + + \sa confirmCancels() confirmEdits() confirmInsert() confirmDelete() +*/ + +bool QDataTable::confirmUpdate() const +{ + return ( d->dat.confirmUpdate() ); +} + +/*! + \property QDataTable::confirmDelete + \brief whether the data table confirms delete operations + + If the confirmDelete property is TRUE, all deletions must be + confirmed by the user through a message box (this behaviour can be + changed by overriding the confirmEdit() function), otherwise all + delete operations occur immediately. + + \sa confirmCancels() confirmEdits() confirmUpdate() confirmInsert() +*/ + +bool QDataTable::confirmDelete() const +{ + return ( d->dat.confirmDelete() ); +} + +/*! + \property QDataTable::confirmCancels + \brief whether the data table confirms cancel operations + + If the confirmCancel property is TRUE, all cancels must be + confirmed by the user through a message box (this behavior can be + changed by overriding the confirmCancel() function), otherwise all + cancels occur immediately. The default is FALSE. + + \sa confirmEdits() confirmCancel() +*/ + +void QDataTable::setConfirmCancels( bool confirm ) +{ + d->dat.setConfirmCancels( confirm ); +} + +bool QDataTable::confirmCancels() const +{ + return d->dat.confirmCancels(); +} + +/*! + \reimp + + For an editable table, creates an editor suitable for the field in + column \a col. The editor is created using the default editor + factory, unless a different editor factory was installed with + installEditorFactory(). The editor is primed with the value of the + field in \a col using a property map. The property map used is the + default property map, unless a new property map was installed with + installPropertMap(). If \a initFromCell is TRUE then the editor is + primed with the value in the QDataTable cell. +*/ + +QWidget * QDataTable::createEditor( int , int col, bool initFromCell ) const +{ + if ( d->dat.mode() == QSql::None ) + return 0; + + QSqlEditorFactory * f = (d->editorFactory == 0) ? + QSqlEditorFactory::defaultFactory() : d->editorFactory; + + QSqlPropertyMap * m = (d->propertyMap == 0) ? + QSqlPropertyMap::defaultMap() : d->propertyMap; + + QWidget * w = 0; + if( initFromCell && d->editBuffer ){ + w = f->createEditor( viewport(), d->editBuffer->field( indexOf( col ) ) ); + if ( w ) + m->setProperty( w, d->editBuffer->value( indexOf( col ) ) ); + } + return w; +} + +/*! \reimp */ +bool QDataTable::eventFilter( QObject *o, QEvent *e ) +{ + if ( d->cancelMode ) + return TRUE; + + int r = currentRow(); + int c = currentColumn(); + + if ( d->dat.mode() != QSql::None ) { + r = d->editRow; + c = d->editCol; + } + + d->cancelInsert = FALSE; + d->cancelUpdate = FALSE; + switch ( e->type() ) { + case QEvent::KeyPress: { + int conf = QSql::Yes; + QKeyEvent *ke = (QKeyEvent*)e; + if ( ( ke->key() == Key_Tab || ke->key() == Qt::Key_BackTab ) + && ke->state() & Qt::ControlButton ) + return FALSE; + + if ( ke->key() == Key_Escape && d->dat.mode() == QSql::Insert ){ + if ( confirmCancels() && !d->cancelMode ) { + d->cancelMode = TRUE; + conf = confirmCancel( QSql::Insert ); + d->cancelMode = FALSE; + } + if ( conf == QSql::Yes ) { + d->cancelInsert = TRUE; + } else { + QWidget *editorWidget = cellWidget( r, c ); + if ( editorWidget ) { + editorWidget->setActiveWindow(); + editorWidget->setFocus(); + } + return TRUE; + } + } + if ( ke->key() == Key_Escape && d->dat.mode() == QSql::Update ) { + if ( confirmCancels() && !d->cancelMode ) { + d->cancelMode = TRUE; + conf = confirmCancel( QSql::Update ); + d->cancelMode = FALSE; + } + if ( conf == QSql::Yes ){ + d->cancelUpdate = TRUE; + } else { + QWidget *editorWidget = cellWidget( r, c ); + if ( editorWidget ) { + editorWidget->setActiveWindow(); + editorWidget->setFocus(); + } + return TRUE; + } + } + if ( ke->key() == Key_Insert && d->dat.mode() == QSql::None ) { + beginInsert(); + return TRUE; + } + if ( ke->key() == Key_Delete && d->dat.mode() == QSql::None ) { + deleteCurrent(); + return TRUE; + } + if ( d->dat.mode() != QSql::None ) { + if ( (ke->key() == Key_Tab) && (c < numCols() - 1) && (!isColumnReadOnly( c+1 ) || d->dat.mode() == QSql::Insert) ) + d->continuousEdit = TRUE; + else if ( (ke->key() == Key_BackTab) && (c > 0) && (!isColumnReadOnly( c-1 ) || d->dat.mode() == QSql::Insert) ) + d->continuousEdit = TRUE; + else + d->continuousEdit = FALSE; + } + QSqlCursor * sql = sqlCursor(); + if ( sql && sql->driver() && + !sql->driver()->hasFeature( QSqlDriver::QuerySize ) && + ke->key() == Key_End && d->dat.mode() == QSql::None ) { +#ifndef QT_NO_CURSOR + QApplication::setOverrideCursor( Qt::WaitCursor ); +#endif + int i = sql->at(); + if ( i < 0 ) { + i = 0; + sql->seek(0); + } + while ( sql->next() ) + i++; + setNumRows( i+1 ); + setCurrentCell( i+1, currentColumn() ); +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif + return TRUE; + } + break; + } + case QEvent::FocusOut: { + QWidget *editorWidget = cellWidget( r, c ); + repaintCell( currentRow(), currentColumn() ); + if ( !d->cancelMode && editorWidget && o == editorWidget && + ( d->dat.mode() == QSql::Insert) && !d->continuousEdit) { + setCurrentCell( r, c ); + d->cancelInsert = TRUE; + } + d->continuousEdit = FALSE; + break; + } + case QEvent::FocusIn: + repaintCell( currentRow(), currentColumn() ); + break; + default: + break; + } + return QTable::eventFilter( o, e ); +} + +/*! \reimp */ +void QDataTable::resizeEvent ( QResizeEvent * e ) +{ + if ( sqlCursor() && + sqlCursor()->driver() && + !sqlCursor()->driver()->hasFeature( QSqlDriver::QuerySize ) ) + loadNextPage(); + QTable::resizeEvent( e ); +} + +/*! \reimp */ +void QDataTable::contentsContextMenuEvent( QContextMenuEvent* e ) +{ + QTable::contentsContextMenuEvent( e ); + if ( isEditing() && d->dat.mode() != QSql::None ) + endEdit( d->editRow, d->editCol, autoEdit(), FALSE ); + if ( !sqlCursor() ) + return; + if ( d->dat.mode() == QSql::None ) { + if ( isReadOnly() ) + return; + enum { + IdInsert, + IdUpdate, + IdDelete + }; + QGuardedPtr<QPopupMenu> popup = new QPopupMenu( this, "qt_datatable_menu" ); + int id[ 3 ]; + id[ IdInsert ] = popup->insertItem( tr( "Insert" ) ); + id[ IdUpdate ] = popup->insertItem( tr( "Update" ) ); + id[ IdDelete ] = popup->insertItem( tr( "Delete" ) ); + bool enableInsert = sqlCursor()->canInsert(); + popup->setItemEnabled( id[ IdInsert ], enableInsert ); + bool enableUpdate = currentRow() > -1 && sqlCursor()->canUpdate() && !isColumnReadOnly( currentColumn() ); + popup->setItemEnabled( id[ IdUpdate ], enableUpdate ); + bool enableDelete = currentRow() > -1 && sqlCursor()->canDelete(); + popup->setItemEnabled( id[ IdDelete ], enableDelete ); + int r = popup->exec( e->globalPos() ); + delete (QPopupMenu*) popup; + if ( r == id[ IdInsert ] ) + beginInsert(); + else if ( r == id[ IdUpdate ] ) { + if ( beginEdit( currentRow(), currentColumn(), FALSE ) ) + setEditMode( Editing, currentRow(), currentColumn() ); + else + endUpdate(); + } + else if ( r == id[ IdDelete ] ) + deleteCurrent(); + e->accept(); + } +} + +/*! \reimp */ +void QDataTable::contentsMousePressEvent( QMouseEvent* e ) +{ + QTable::contentsMousePressEvent( e ); +} + +/*! \reimp */ +QWidget* QDataTable::beginEdit ( int row, int col, bool replace ) +{ + d->editRow = -1; + d->editCol = -1; + if ( !sqlCursor() ) + return 0; + if ( d->dat.mode() == QSql::Insert && !sqlCursor()->canInsert() ) + return 0; + if ( d->dat.mode() == QSql::Update && !sqlCursor()->canUpdate() ) + return 0; + d->editRow = row; + d->editCol = col; + if ( d->continuousEdit ) { + // see comment in beginInsert() + bool fakeReadOnly = isColumnReadOnly( col ); + setColumnReadOnly( col, FALSE ); + QWidget* w = QTable::beginEdit( row, col, replace ); + setColumnReadOnly( col, fakeReadOnly ); + return w; + } + if ( d->dat.mode() == QSql::None && sqlCursor()->canUpdate() && sqlCursor()->primaryIndex().count() > 0 ) + return beginUpdate( row, col, replace ); + return 0; +} + +/*! \reimp */ +void QDataTable::endEdit( int row, int col, bool, bool ) +{ + bool accept = autoEdit() && !d->cancelInsert && !d->cancelUpdate; + + QWidget *editor = cellWidget( row, col ); + if ( !editor ) + return; + if ( d->cancelMode ) + return; + if ( d->dat.mode() != QSql::None && d->editBuffer ) { + QSqlPropertyMap * m = (d->propertyMap == 0) ? + QSqlPropertyMap::defaultMap() : d->propertyMap; + d->editBuffer->setValue( indexOf( col ), m->property( editor ) ); + clearCellWidget( row, col ); + if ( !d->continuousEdit ) { + switch ( d->dat.mode() ) { + case QSql::Insert: + if ( accept ) + QTimer::singleShot( 0, this, SLOT( doInsertCurrent() ) ); + else + endInsert(); + break; + case QSql::Update: + if ( accept ) + QTimer::singleShot( 0, this, SLOT( doUpdateCurrent() ) ); + else + endUpdate(); + break; + default: + break; + } + } + } else { + setEditMode( NotEditing, -1, -1 ); + } + if ( d->dat.mode() == QSql::None ) + viewport()->setFocus(); + updateCell( row, col ); + emit valueChanged( row, col ); +} + +/*! \internal */ +void QDataTable::doInsertCurrent() +{ + insertCurrent(); +} + +/*! \internal */ +void QDataTable::doUpdateCurrent() +{ + updateCurrent(); + if ( d->dat.mode() == QSql::None ) { + viewport()->setFocus(); + } +} + +/*! \reimp */ +void QDataTable::activateNextCell() +{ +// if ( d->dat.mode() == QSql::None ) +// QTable::activateNextCell(); +} + +/*! \internal +*/ + +void QDataTable::endInsert() +{ + if ( d->dat.mode() != QSql::Insert ) + return; + d->dat.setMode( QSql::None ); + d->editBuffer = 0; + verticalHeader()->setLabel( d->editRow, QString::number( d->editRow +1 ) ); + d->editRow = -1; + d->editCol = -1; + d->insertRowLast = -1; + d->insertHeaderLabelLast = QString::null; + setEditMode( NotEditing, -1, -1 ); + setNumRows( d->insertPreRows ); + d->insertPreRows = -1; + viewport()->setFocus(); +} + +/*! \internal +*/ + +void QDataTable::endUpdate() +{ + d->dat.setMode( QSql::None ); + d->editBuffer = 0; + updateRow( d->editRow ); + d->editRow = -1; + d->editCol = -1; + setEditMode( NotEditing, -1, -1 ); +} + +/*! + Protected virtual function called when editing is about to begin + on a new record. If the table is read-only, or if there's no + cursor or the cursor does not allow inserts, nothing happens. + + Editing takes place using the cursor's edit buffer(see + QSqlCursor::editBuffer()). + + When editing begins, a new row is created in the table marked with + an asterisk '*' in the row's vertical header column, i.e. at the + left of the row. +*/ + +bool QDataTable::beginInsert() +{ + if ( !sqlCursor() || isReadOnly() || !numCols() ) + return FALSE; + if ( !sqlCursor()->canInsert() ) + return FALSE; + int i = 0; + int row = currentRow(); + + d->insertPreRows = numRows(); + if ( row < 0 || numRows() < 1 ) + row = 0; + setNumRows( d->insertPreRows + 1 ); + setCurrentCell( row, 0 ); + d->editBuffer = sqlCursor()->primeInsert(); + emit primeInsert( d->editBuffer ); + d->dat.setMode( QSql::Insert ); + int lastRow = row; + int lastY = contentsY() + visibleHeight(); + for ( i = row; i < numRows() ; ++i ) { + QRect cg = cellGeometry( i, 0 ); + if ( (cg.y()+cg.height()) > lastY ) { + lastRow = i; + break; + } + } + if ( lastRow == row && ( numRows()-1 > row ) ) + lastRow = numRows() - 1; + d->insertRowLast = lastRow; + d->insertHeaderLabelLast = verticalHeader()->label( d->insertRowLast ); + verticalHeader()->setLabel( row, "*" ); + d->editRow = row; + // in the db world it's common to allow inserting new records + // into a table that has read-only columns - temporarily + // switch off read-only mode for such columns + bool fakeReadOnly = isColumnReadOnly( 0 ); + setColumnReadOnly( 0, FALSE ); + if ( QTable::beginEdit( row, 0, FALSE ) ) + setEditMode( Editing, row, 0 ); + setColumnReadOnly( 0, fakeReadOnly ); + return TRUE; +} + +/*! + Protected virtual function called when editing is about to begin + on an existing row. If the table is read-only, or if there's no + cursor, nothing happens. + + Editing takes place using the cursor's edit buffer (see + QSqlCursor::editBuffer()). + + \a row and \a col refer to the row and column in the QDataTable. + + (\a replace is provided for reimplementors and reflects the API of + QTable::beginEdit().) +*/ + +QWidget* QDataTable::beginUpdate ( int row, int col, bool replace ) +{ + if ( !sqlCursor() || isReadOnly() || isColumnReadOnly( col ) ) + return 0; + setCurrentCell( row, col ); + d->dat.setMode( QSql::Update ); + if ( sqlCursor()->seek( row ) ) { + d->editBuffer = sqlCursor()->primeUpdate(); + sqlCursor()->seek( currentRow() ); + emit primeUpdate( d->editBuffer ); + return QTable::beginEdit( row, col, replace ); + } + return 0; +} + +/*! + For an editable table, issues an insert on the current cursor + using the values in the cursor's edit buffer. If there is no + current cursor or there is no current "insert" row, nothing + happens. If confirmEdits() or confirmInsert() is TRUE, + confirmEdit() is called to confirm the insert. Returns TRUE if the + insert succeeded; otherwise returns FALSE. + + The underlying cursor must have a valid primary index to ensure + that a unique record is inserted within the database otherwise the + database may be changed to an inconsistent state. +*/ + +bool QDataTable::insertCurrent() +{ + if ( d->dat.mode() != QSql::Insert || ! numCols() ) + return FALSE; + if ( !sqlCursor()->canInsert() ) { +#ifdef QT_CHECK_RANGE + qWarning("QDataTable::insertCurrent: insert not allowed for %s", + sqlCursor()->name().latin1() ); +#endif + endInsert(); + return FALSE; + } + int b = 0; + int conf = QSql::Yes; + if ( confirmEdits() || confirmInsert() ) + conf = confirmEdit( QSql::Insert ); + switch ( conf ) { + case QSql::Yes: { +#ifndef QT_NO_CURSOR + QApplication::setOverrideCursor( Qt::waitCursor ); +#endif + emit beforeInsert( d->editBuffer ); + b = sqlCursor()->insert(); +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif + if ( ( !b && !sqlCursor()->isActive() ) || !sqlCursor()->isActive() ) { + handleError( sqlCursor()->lastError() ); + endInsert(); // cancel the insert if anything goes wrong + refresh(); + } else { + endInsert(); + refresh(); + QSqlIndex idx = sqlCursor()->primaryIndex(); + findBuffer( idx, d->lastAt ); + repaintContents( contentsX(), contentsY(), visibleWidth(), visibleHeight(), FALSE ); + emit cursorChanged( QSql::Insert ); + } + break; + } + case QSql::No: + endInsert(); + break; + case QSql::Cancel: + if ( QTable::beginEdit( currentRow(), currentColumn(), FALSE ) ) + setEditMode( Editing, currentRow(), currentColumn() ); + break; + } + return ( b > 0 ); +} + +/*! \internal + + Updates the row \a row. +*/ + +void QDataTable::updateRow( int row ) +{ + for ( int i = 0; i < numCols(); ++i ) + updateCell( row, i ); +} + +/*! + For an editable table, issues an update using the cursor's edit + buffer. If there is no current cursor or there is no current + selection, nothing happens. If confirmEdits() or confirmUpdate() + is TRUE, confirmEdit() is called to confirm the update. Returns + TRUE if the update succeeded; otherwise returns FALSE. + + The underlying cursor must have a valid primary index to ensure + that a unique record is updated within the database otherwise the + database may be changed to an inconsistent state. +*/ + +bool QDataTable::updateCurrent() +{ + if ( d->dat.mode() != QSql::Update ) + return FALSE; + if ( sqlCursor()->primaryIndex().count() == 0 ) { +#ifdef QT_CHECK_RANGE + qWarning("QDataTable::updateCurrent: no primary index for %s", + sqlCursor()->name().latin1() ); +#endif + endUpdate(); + return FALSE; + } + if ( !sqlCursor()->canUpdate() ) { +#ifdef QT_CHECK_RANGE + qWarning("QDataTable::updateCurrent: updates not allowed for %s", + sqlCursor()->name().latin1() ); +#endif + endUpdate(); + return FALSE; + } + int b = 0; + int conf = QSql::Yes; + if ( confirmEdits() || confirmUpdate() ) + conf = confirmEdit( QSql::Update ); + switch ( conf ) { + case QSql::Yes: { +#ifndef QT_NO_CURSOR + QApplication::setOverrideCursor( Qt::waitCursor ); +#endif + emit beforeUpdate( d->editBuffer ); + b = sqlCursor()->update(); +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif + if ( ( !b && !sqlCursor()->isActive() ) || !sqlCursor()->isActive() ) { + handleError( sqlCursor()->lastError() ); + endUpdate(); + refresh(); + setCurrentCell( d->editRow, d->editCol ); + if ( QTable::beginEdit( d->editRow, d->editCol, FALSE ) ) + setEditMode( Editing, d->editRow, d->editCol ); + } else { + emit cursorChanged( QSql::Update ); + refresh(); + endUpdate(); + } + break; + } + case QSql::No: + endUpdate(); + setEditMode( NotEditing, -1, -1 ); + break; + case QSql::Cancel: + setCurrentCell( d->editRow, d->editCol ); + if ( QTable::beginEdit( d->editRow, d->editCol, FALSE ) ) + setEditMode( Editing, d->editRow, d->editCol ); + break; + } + return ( b > 0 ); +} + +/*! + For an editable table, issues a delete on the current cursor's + primary index using the values of the currently selected row. If + there is no current cursor or there is no current selection, + nothing happens. If confirmEdits() or confirmDelete() is TRUE, + confirmEdit() is called to confirm the delete. Returns TRUE if the + delete succeeded; otherwise FALSE. + + The underlying cursor must have a valid primary index to ensure + that a unique record is deleted within the database otherwise the + database may be changed to an inconsistent state. +*/ + +bool QDataTable::deleteCurrent() +{ + if ( !sqlCursor() || isReadOnly() ) + return FALSE; + if ( sqlCursor()->primaryIndex().count() == 0 ) { +#ifdef QT_CHECK_RANGE + qWarning("QDataTable::deleteCurrent: no primary index %s", + sqlCursor()->name().latin1() ); +#endif + return FALSE; + } + if ( !sqlCursor()->canDelete() ) + return FALSE; + + int b = 0; + int conf = QSql::Yes; + if ( confirmEdits() || confirmDelete() ) + conf = confirmEdit( QSql::Delete ); + + // Have to have this here - the confirmEdit() might pop up a + // dialog that causes a repaint which the cursor to the + // record it has to repaint. + if ( !sqlCursor()->seek( currentRow() ) ) + return FALSE; + switch ( conf ) { + case QSql::Yes:{ +#ifndef QT_NO_CURSOR + QApplication::setOverrideCursor( Qt::waitCursor ); +#endif + sqlCursor()->primeDelete(); + emit primeDelete( sqlCursor()->editBuffer() ); + emit beforeDelete( sqlCursor()->editBuffer() ); + b = sqlCursor()->del(); +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif + if ( !b ) + handleError( sqlCursor()->lastError() ); + refresh(); + emit cursorChanged( QSql::Delete ); + setCurrentCell( currentRow(), currentColumn() ); + repaintContents( contentsX(), contentsY(), visibleWidth(), visibleHeight(), FALSE ); + verticalHeader()->repaint(); // get rid of trailing garbage + } + break; + case QSql::No: + setEditMode( NotEditing, -1, -1 ); + break; + } + return ( b > 0 ); +} + +/*! + Protected virtual function which returns a confirmation for an + edit of mode \a m. Derived classes can reimplement this function + to provide their own confirmation dialog. The default + implementation uses a message box which prompts the user to + confirm the edit action. +*/ + +QSql::Confirm QDataTable::confirmEdit( QSql::Op m ) +{ + return d->dat.confirmEdit( this, m ); +} + +/*! + Protected virtual function which returns a confirmation for + cancelling an edit mode of \a m. Derived classes can reimplement + this function to provide their own cancel dialog. The default + implementation uses a message box which prompts the user to + confirm the cancel. +*/ + +QSql::Confirm QDataTable::confirmCancel( QSql::Op m ) +{ + return d->dat.confirmCancel( this, m ); +} + + +/*! + Searches the current cursor for a cell containing the string \a + str starting at the current cell and working forwards (or + backwards if \a backwards is TRUE). If the string is found, the + cell containing the string is set as the current cell. If \a + caseSensitive is FALSE the case of \a str will be ignored. + + The search will wrap, i.e. if the first (or if backwards is TRUE, + last) cell is reached without finding \a str the search will + continue until it reaches the starting cell. If \a str is not + found the search will fail and the current cell will remain + unchanged. +*/ +void QDataTable::find( const QString & str, bool caseSensitive, bool backwards ) +{ + if ( !sqlCursor() ) + return; + + QSqlCursor * r = sqlCursor(); + QString tmp, text; + uint row = currentRow(), startRow = row, + col = backwards ? currentColumn() - 1 : currentColumn() + 1; + bool wrap = TRUE, found = FALSE; + + if( str.isEmpty() || str.isNull() ) + return; + + if( !caseSensitive ) + tmp = str.lower(); + else + tmp = str; + +#ifndef QT_NO_CURSOR + QApplication::setOverrideCursor( Qt::waitCursor ); +#endif + while( wrap ){ + while( !found && r->seek( row ) ){ + for( int i = col; backwards ? (i >= 0) : (i < (int) numCols()); + backwards ? i-- : i++ ) + { + text = r->value( indexOf( i ) ).toString(); + if( !caseSensitive ){ + text = text.lower(); + } + if( text.contains( tmp ) ){ + setCurrentCell( row, i ); + col = i; + found = TRUE; + } + } + if( !backwards ){ + col = 0; + row++; + } else { + col = numCols() - 1; + row--; + } + } + if( !backwards ){ + if( startRow != 0 ){ + startRow = 0; + } else { + wrap = FALSE; + } + r->first(); + row = 0; + } else { + if( startRow != (uint) (numRows() - 1) ){ + startRow = numRows() - 1; + } else { + wrap = FALSE; + } + r->last(); + row = numRows() - 1; + } + } +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif +} + + +/*! + Resets the table so that it displays no data. + + \sa setSqlCursor() +*/ + +void QDataTable::reset() +{ + clearCellWidget( currentRow(), currentColumn() ); + switch ( d->dat.mode() ) { + case QSql::Insert: + endInsert(); + break; + case QSql::Update: + endUpdate(); + break; + default: + break; + } + ensureVisible( 0, 0 ); + verticalScrollBar()->setValue(0); + setNumRows(0); + + d->haveAllRows = FALSE; + d->continuousEdit = FALSE; + d->dat.setMode( QSql::None ); + d->editRow = -1; + d->editCol = -1; + d->insertRowLast = -1; + d->insertHeaderLabelLast = QString::null; + d->cancelMode = FALSE; + d->lastAt = -1; + d->fld.clear(); + d->fldLabel.clear(); + d->fldWidth.clear(); + d->fldIcon.clear(); + d->fldHidden.clear(); + if ( sorting() ) + horizontalHeader()->setSortIndicator( -1 ); +} + +/*! + Returns the index of the field within the current SQL query that + is displayed in column \a i. +*/ + +int QDataTable::indexOf( uint i ) const +{ + QDataTablePrivate::ColIndex::ConstIterator it = d->colIndex.at( i ); + if ( it != d->colIndex.end() ) + return *it; + return -1; +} + +/*! + Returns TRUE if the table will automatically delete the cursor + specified by setSqlCursor(); otherwise returns FALSE. +*/ + +bool QDataTable::autoDelete() const +{ + return d->cur.autoDelete(); +} + +/*! + Sets the cursor auto-delete flag to \a enable. If \a enable is + TRUE, the table will automatically delete the cursor specified by + setSqlCursor(). If \a enable is FALSE (the default), the cursor + will not be deleted. +*/ + +void QDataTable::setAutoDelete( bool enable ) +{ + d->cur.setAutoDelete( enable ); +} + +/*! + \property QDataTable::autoEdit + \brief whether the data table automatically applies edits + + The default value for this property is TRUE. When the user begins + an insert or update in the table there are two possible outcomes + when they navigate to another record: + + \list 1 + \i the insert or update is is performed -- this occurs if autoEdit is TRUE + \i the insert or update is abandoned -- this occurs if autoEdit is FALSE + \endlist +*/ + +void QDataTable::setAutoEdit( bool autoEdit ) +{ + d->dat.setAutoEdit( autoEdit ); +} + +bool QDataTable::autoEdit() const +{ + return d->dat.autoEdit(); +} + +/*! + \property QDataTable::nullText + \brief the text used to represent NULL values + + The nullText property will be used to represent NULL values in the + table. The default value is provided by the cursor's driver. +*/ + +void QDataTable::setNullText( const QString& nullText ) +{ + d->nullTxt = nullText; + d->nullTxtChanged = TRUE; +} + +QString QDataTable::nullText() const +{ + return d->nullTxt; +} + +/*! + \property QDataTable::trueText + \brief the text used to represent true values + + The trueText property will be used to represent NULL values in the + table. The default value is "True". +*/ + +void QDataTable::setTrueText( const QString& trueText ) +{ + d->trueTxt = trueText; +} + +QString QDataTable::trueText() const +{ + return d->trueTxt; +} + +/*! + \property QDataTable::falseText + \brief the text used to represent false values + + The falseText property will be used to represent NULL values in + the table. The default value is "False". +*/ + +void QDataTable::setFalseText( const QString& falseText ) +{ + d->falseTxt = falseText; +} + +QString QDataTable::falseText() const +{ + return d->falseTxt; +} + +/*! + \property QDataTable::dateFormat + \brief the format used for displaying date/time values + + The dateFormat property is used for displaying date/time values in + the table. The default value is \c Qt::LocalDate. +*/ + +void QDataTable::setDateFormat( const DateFormat f ) +{ + d->datefmt = f; +} + +Qt::DateFormat QDataTable::dateFormat() const +{ + return d->datefmt; +} + +/*! + \property QDataTable::numRows + + \brief the number of rows in the table +*/ + +int QDataTable::numRows() const +{ + return QTable::numRows(); +} + +/*! + \reimp + + The number of rows in the table will be determined by the cursor + (see setSqlCursor()), so normally this function should never be + called. It is included for completeness. +*/ + +void QDataTable::setNumRows ( int r ) +{ + QTable::setNumRows( r ); +} + +/*! + \reimp + + The number of columns in the table will be determined + automatically (see addColumn()), so normally this function should + never be called. It is included for completeness. +*/ + +void QDataTable::setNumCols ( int r ) +{ + QTable::setNumCols( r ); +} + +/*! + \property QDataTable::numCols + + \brief the number of columns in the table +*/ + +int QDataTable::numCols() const +{ + return QTable::numCols(); +} + +/*! + Returns the text in cell \a row, \a col, or an empty string if the + cell is empty. If the cell's value is NULL then nullText() will be + returned. If the cell does not exist then QString::null is + returned. +*/ + +QString QDataTable::text ( int row, int col ) const +{ + if ( !sqlCursor() ) + return QString::null; + + QString s; + if ( sqlCursor()->seek( row ) ) + s = sqlCursor()->value( indexOf( col ) ).toString(); + sqlCursor()->seek( currentRow() ); + return s; +} + +/*! + Returns the value in cell \a row, \a col, or an invalid value if + the cell does not exist or has no value. +*/ + +QVariant QDataTable::value ( int row, int col ) const +{ + if ( !sqlCursor() ) + return QVariant(); + + QVariant v; + if ( sqlCursor()->seek( row ) ) + v = sqlCursor()->value( indexOf( col ) ); + sqlCursor()->seek( currentRow() ); + return v; +} + +/*! \internal + Used to update the table when the size of the result set cannot be + determined - divide the result set into pages and load the pages as + the user moves around in the table. +*/ +void QDataTable::loadNextPage() +{ + if ( d->haveAllRows ) + return; + if ( !sqlCursor() ) + return; + int pageSize = 0; + int lookAhead = 0; + if ( height() ) { + pageSize = (int)( height() * 2 / 20 ); + lookAhead = pageSize / 2; + } + int startIdx = verticalScrollBar()->value() / 20; + int endIdx = startIdx + pageSize + lookAhead; + if ( endIdx < numRows() || endIdx < 0 ) + return; + + // check for empty result set + if ( sqlCursor()->at() == QSql::BeforeFirst && !sqlCursor()->next() ) { + d->haveAllRows = TRUE; + return; + } + + while ( endIdx > 0 && !sqlCursor()->seek( endIdx ) ) + endIdx--; + if ( endIdx != ( startIdx + pageSize + lookAhead ) ) + d->haveAllRows = TRUE; + // small hack to prevent QTable from moving the view when a row + // is selected and the contents is resized + SelectionMode m = selectionMode(); + clearSelection(); + setSelectionMode( NoSelection ); + setNumRows( endIdx + 1 ); + sqlCursor()->seek( currentRow() ); + setSelectionMode( m ); +} + +/*! \internal */ +void QDataTable::sliderPressed() +{ + disconnect( verticalScrollBar(), SIGNAL( valueChanged(int) ), + this, SLOT( loadNextPage() ) ); +} + +/*! \internal */ +void QDataTable::sliderReleased() +{ + loadNextPage(); + connect( verticalScrollBar(), SIGNAL( valueChanged(int) ), + this, SLOT( loadNextPage() ) ); +} + +/*! + Sorts column \a col in ascending order if \a ascending is TRUE + (the default); otherwise sorts in descending order. + + The \a wholeRows parameter is ignored; QDataTable always sorts + whole rows by the specified column. +*/ + +void QDataTable::sortColumn ( int col, bool ascending, + bool ) +{ + if ( sorting() ) { + if ( isEditing() && d->dat.mode() != QSql::None ) + endEdit( d->editRow, d->editCol, autoEdit(), FALSE ); + if ( !sqlCursor() ) + return; + QSqlIndex lastSort = sqlCursor()->sort(); + QSqlIndex newSort( lastSort.cursorName(), "newSort" ); + QSqlField *field = sqlCursor()->field( indexOf( col ) ); + if ( field ) + newSort.append( *field ); + newSort.setDescending( 0, !ascending ); + horizontalHeader()->setSortIndicator( col, ascending ); + setSort( newSort ); + refresh(); + } +} + +/*! \reimp */ +void QDataTable::columnClicked ( int col ) +{ + if ( sorting() ) { + if ( !sqlCursor() ) + return; + QSqlIndex lastSort = sqlCursor()->sort(); + bool asc = TRUE; + if ( lastSort.count() && lastSort.field( 0 )->name() == sqlCursor()->field( indexOf( col ) )->name() ) + asc = lastSort.isDescending( 0 ); + sortColumn( col, asc ); + emit currentChanged( sqlCursor() ); + } +} + +/*! + \reimp + + Repaints the cell at \a row, \a col. +*/ +void QDataTable::repaintCell( int row, int col ) +{ + QRect cg = cellGeometry( row, col ); + QRect re( QPoint( cg.x() - 2, cg.y() - 2 ), + QSize( cg.width() + 4, cg.height() + 4 ) ); + repaintContents( re, FALSE ); +} + +/*! + \reimp + + This function renders the cell at \a row, \a col with the value of + the corresponding cursor field on the painter \a p. Depending on + the table's current edit mode, paintField() is called for the + appropriate cursor field. \a cr describes the cell coordinates in + the content coordinate system. If \a selected is TRUE the cell has + been selected and would normally be rendered differently than an + unselected cell. + + \sa QSql::isNull() +*/ + +void QDataTable::paintCell( QPainter * p, int row, int col, const QRect & cr, + bool selected, const QColorGroup &cg ) +{ + QTable::paintCell( p, row, col, cr, selected, cg ); // empty cell + + if ( !sqlCursor() ) + return; + + p->setPen( selected ? cg.highlightedText() : cg.text() ); + if ( d->dat.mode() != QSql::None ) { + if ( row == d->editRow && d->editBuffer ) { + paintField( p, d->editBuffer->field( indexOf( col ) ), cr, + selected ); + } else if ( row > d->editRow && d->dat.mode() == QSql::Insert ) { + if ( sqlCursor()->seek( row - 1 ) ) + paintField( p, sqlCursor()->field( indexOf( col ) ), cr, + selected ); + } else { + if ( sqlCursor()->seek( row ) ) + paintField( p, sqlCursor()->field( indexOf( col ) ), cr, + selected ); + } + } else { + if ( sqlCursor()->seek( row ) ) + paintField( p, sqlCursor()->field( indexOf( col ) ), cr, selected ); + + } +} + + +/*! + Paints the \a field on the painter \a p. The painter has already + been translated to the appropriate cell's origin where the \a + field is to be rendered. \a cr describes the cell coordinates in + the content coordinate system. The \a selected parameter is + ignored. + + If you want to draw custom field content you must reimplement + paintField() to do the custom drawing. The default implementation + renders the \a field value as text. If the field is NULL, + nullText() is displayed in the cell. If the field is Boolean, + trueText() or falseText() is displayed as appropriate. +*/ + +void QDataTable::paintField( QPainter * p, const QSqlField* field, + const QRect & cr, bool ) +{ + if ( !field ) + return; + p->drawText( 2,2, cr.width()-4, cr.height()-4, fieldAlignment( field ), fieldToString( field ) ); +} + +/*! + Returns the alignment for \a field. +*/ + +int QDataTable::fieldAlignment( const QSqlField* /*field*/ ) +{ + return Qt::AlignLeft | Qt::AlignVCenter; //## Reggie: add alignment to QTable +} + + +/*! + If the cursor's \a sql driver supports query sizes, the number of + rows in the table is set to the size of the query. Otherwise, the + table dynamically resizes itself as it is scrolled. If \a sql is + not active, it is made active by issuing a select() on the cursor + using the \a sql cursor's current filter and current sort. +*/ + +void QDataTable::setSize( QSqlCursor* sql ) +{ + // ### what are the connect/disconnect calls doing here!? move to refresh() + if ( sql->driver() && sql->driver()->hasFeature( QSqlDriver::QuerySize ) ) { + setVScrollBarMode( Auto ); + disconnect( verticalScrollBar(), SIGNAL( sliderPressed() ), + this, SLOT( sliderPressed() ) ); + disconnect( verticalScrollBar(), SIGNAL( sliderReleased() ), + this, SLOT( sliderReleased() ) ); + disconnect( verticalScrollBar(), SIGNAL( valueChanged(int) ), + this, SLOT( loadNextPage() ) ); + if ( numRows() != sql->size() ) + setNumRows( sql->size() ); + } else { + setVScrollBarMode( AlwaysOn ); + connect( verticalScrollBar(), SIGNAL( sliderPressed() ), + this, SLOT( sliderPressed() ) ); + connect( verticalScrollBar(), SIGNAL( sliderReleased() ), + this, SLOT( sliderReleased() ) ); + connect( verticalScrollBar(), SIGNAL( valueChanged(int) ), + this, SLOT( loadNextPage() ) ); + setNumRows(0); + loadNextPage(); + } +} + +/*! + Sets \a cursor as the data source for the table. To force the + display of the data from \a cursor, use refresh(). If \a + autoPopulate is TRUE, columns are automatically created based upon + the fields in the \a cursor record. If \a autoDelete is TRUE (the + default is FALSE), the table will take ownership of the \a cursor + and delete it when appropriate. If the \a cursor is read-only, the + table becomes read-only. The table adopts the cursor's driver's + definition for representing NULL values as strings. + + \sa refresh() setReadOnly() setAutoDelete() QSqlDriver::nullText() +*/ + +void QDataTable::setSqlCursor( QSqlCursor* cursor, bool autoPopulate, bool autoDelete ) +{ + setUpdatesEnabled( FALSE ); + d->cur.setCursor( 0 ); + if ( cursor ) { + d->cur.setCursor( cursor, autoDelete ); + if ( autoPopulate ) { + d->fld.clear(); + d->fldLabel.clear(); + d->fldWidth.clear(); + d->fldIcon.clear(); + d->fldHidden.clear(); + for ( uint i = 0; i < sqlCursor()->count(); ++i ) { + addColumn( sqlCursor()->field( i )->name(), sqlCursor()->field( i )->name() ); + setColumnReadOnly( i, sqlCursor()->field( i )->isReadOnly() ); + } + } + setReadOnly( sqlCursor()->isReadOnly() ); + if ( sqlCursor()->driver() && !d->nullTxtChanged ) + setNullText(sqlCursor()->driver()->nullText() ); + setAutoDelete( autoDelete ); + } else { + setNumRows( 0 ); + setNumCols( 0 ); + } + setUpdatesEnabled( TRUE ); +} + + +/*! + Protected virtual function which is called when an error \a e has + occurred on the current cursor(). The default implementation + displays a warning message to the user with information about the + error. +*/ +void QDataTable::handleError( const QSqlError& e ) +{ + d->dat.handleError( this, e ); +} + +/*! \reimp + */ + +void QDataTable::keyPressEvent( QKeyEvent* e ) +{ + switch( e->key() ) { + case Key_Left: + case Key_Right: + case Key_Up: + case Key_Down: + case Key_Prior: + case Key_Next: + case Key_Home: + case Key_End: + case Key_F2: + case Key_Enter: case Key_Return: + case Key_Tab: case Key_BackTab: + QTable::keyPressEvent( e ); + default: + return; + } +} + +/*! \reimp +*/ + +void QDataTable::resizeData ( int ) +{ + +} + +/*! \reimp +*/ + +QTableItem * QDataTable::item ( int, int ) const +{ + return 0; +} + +/*! \reimp +*/ + +void QDataTable::setItem ( int , int , QTableItem * ) +{ + +} + +/*! \reimp +*/ + +void QDataTable::clearCell ( int , int ) +{ + +} + +/*! \reimp +*/ + +void QDataTable::setPixmap ( int , int , const QPixmap & ) +{ + +} + +/*! \reimp */ +void QDataTable::takeItem ( QTableItem * ) +{ + +} + +/*! + Installs a new SQL editor factory \a f. This enables the user to + create and instantiate their own editors for use in cell editing. + Note that QDataTable takes ownership of this pointer, and will + delete it when it is no longer needed or when + installEditorFactory() is called again. + + \sa QSqlEditorFactory +*/ + +void QDataTable::installEditorFactory( QSqlEditorFactory * f ) +{ + if( f ) { + delete d->editorFactory; + d->editorFactory = f; + } +} + +/*! + Installs a new property map \a m. This enables the user to create + and instantiate their own property maps for use in cell editing. + Note that QDataTable takes ownership of this pointer, and will + delete it when it is no longer needed or when installPropertMap() + is called again. + + \sa QSqlPropertyMap +*/ + +void QDataTable::installPropertyMap( QSqlPropertyMap* m ) +{ + if ( m ) { + delete d->propertyMap; + d->propertyMap = m; + } +} + +/*! \internal + + Sets the current selection to \a row, \a col. +*/ + +void QDataTable::setCurrentSelection( int row, int ) +{ + if ( !sqlCursor() ) + return; + if ( row == d->lastAt ) + return; + if ( !sqlCursor()->seek( row ) ) + return; + d->lastAt = row; + emit currentChanged( sqlCursor() ); +} + +void QDataTable::updateCurrentSelection() +{ + setCurrentSelection( currentRow(), -1 ); +} + +/*! + Returns the currently selected record, or 0 if there is no current + selection. The table owns the pointer, so do \e not delete it or + otherwise modify it or the cursor it points to. +*/ + +QSqlRecord* QDataTable::currentRecord() const +{ + if ( !sqlCursor() || currentRow() < 0 ) + return 0; + if ( !sqlCursor()->seek( currentRow() ) ) + return 0; + return sqlCursor(); +} + +/*! + Sorts column \a col in ascending order. + + \sa setSorting() +*/ + +void QDataTable::sortAscending( int col ) +{ + sortColumn( col, TRUE ); +} + +/*! + Sorts column \a col in descending order. + + \sa setSorting() +*/ + +void QDataTable::sortDescending( int col ) +{ + sortColumn( col, FALSE ); +} + +/*! + \overload void QDataTable::refresh( Refresh mode ) + + Refreshes the table. If there is no currently defined cursor (see + setSqlCursor()), nothing happens. The \a mode parameter determines + which type of refresh will take place. + + \sa Refresh setSqlCursor() addColumn() +*/ + +void QDataTable::refresh( QDataTable::Refresh mode ) +{ + QSqlCursor* cur = sqlCursor(); + if ( !cur ) + return; + bool refreshData = ( (mode & RefreshData) == RefreshData ); + bool refreshCol = ( (mode & RefreshColumns) == RefreshColumns ); + if ( ( (mode & RefreshAll) == RefreshAll ) ) { + refreshData = TRUE; + refreshCol = TRUE; + } + if ( !refreshCol && d->fld.count() && numCols() == 0 ) + refreshCol = TRUE; + viewport()->setUpdatesEnabled( FALSE ); + d->haveAllRows = FALSE; + if ( refreshData ) { + if ( !d->cur.refresh() && d->cur.cursor() ) { + handleError( d->cur.cursor()->lastError() ); + } + d->lastAt = -1; + } + if ( refreshCol ) { + setNumCols( 0 ); + d->colIndex.clear(); + if ( d->fld.count() ) { + QSqlField* field = 0; + int i; + int fpos = -1; + for ( i = 0; i < (int)d->fld.count(); ++i ) { + if ( cur->field( i ) && cur->field( i )->name() == d->fld[ i ] ) + // if there is a field with the desired name on the desired position + // then we take that + fpos = i; + else + // otherwise we take the first field that matches the desired name + fpos = cur->position( d->fld[ i ] ); + field = cur->field( fpos ); + if ( field && ( cur->isGenerated( fpos ) || + cur->isCalculated( field->name() ) ) ) + { + setNumCols( numCols() + 1 ); + d->colIndex.append( fpos ); + setColumnReadOnly( numCols()-1, field->isReadOnly() || isColumnReadOnly( numCols()-1 ) ); + horizontalHeader()->setLabel( numCols()-1, d->fldIcon[ i ], d->fldLabel[ i ] ); + if ( d->fldHidden[ i ] ) { + QTable::showColumn( i ); // ugly but necessary + QTable::hideColumn( i ); + } else { + QTable::showColumn( i ); + } + if ( d->fldWidth[ i ] > -1 ) + QTable::setColumnWidth( i, d->fldWidth[i] ); + } + } + } + } + viewport()->setUpdatesEnabled( TRUE ); + viewport()->repaint( FALSE ); + horizontalHeader()->repaint(); + verticalHeader()->repaint(); + setSize( cur ); + // keep others aware + if ( d->lastAt == -1 ) + setCurrentSelection( -1, -1 ); + else if ( d->lastAt != currentRow() ) + setCurrentSelection( currentRow(), currentColumn() ); + if ( cur->isValid() ) + emit currentChanged( sqlCursor() ); +} + +/*! + Refreshes the table. The cursor is refreshed using the current + filter, the current sort, and the currently defined columns. + Equivalent to calling refresh( QDataTable::RefreshData ). +*/ + +void QDataTable::refresh() +{ + refresh( RefreshData ); +} + +/*! + \reimp + + Selects the record in the table using the current cursor edit + buffer and the fields specified by the index \a idx. If \a atHint + is specified, it will be used as a hint about where to begin + searching. +*/ + +bool QDataTable::findBuffer( const QSqlIndex& idx, int atHint ) +{ + QSqlCursor* cur = sqlCursor(); + if ( !cur ) + return FALSE; + bool found = d->cur.findBuffer( idx, atHint ); + if ( found ) + setCurrentCell( cur->at(), currentColumn() ); + return found; +} + +/*! \internal + Returns the string representation of a database field. +*/ +QString QDataTable::fieldToString( const QSqlField * field ) +{ + QString text; + if ( field->isNull() ) { + text = nullText(); + } else { + QVariant val = field->value(); + switch ( val.type() ) { + case QVariant::Bool: + text = val.toBool() ? d->trueTxt : d->falseTxt; + break; + case QVariant::Date: + text = val.toDate().toString( d->datefmt ); + break; + case QVariant::Time: + text = val.toTime().toString( d->datefmt ); + break; + case QVariant::DateTime: + text = val.toDateTime().toString( d->datefmt ); + break; + default: + text = val.toString(); + break; + } + } + return text; +} + +/*! + \reimp +*/ + +void QDataTable::swapColumns( int col1, int col2, bool ) +{ + QString fld = d->fld[ col1 ]; + QString fldLabel = d->fldLabel[ col1 ]; + QIconSet fldIcon = d->fldIcon[ col1 ]; + int fldWidth = d->fldWidth[ col1 ]; + + d->fld[ col1 ] = d->fld[ col2 ]; + d->fldLabel[ col1 ] = d->fldLabel[ col2 ]; + d->fldIcon[ col1 ] = d->fldIcon[ col2 ]; + d->fldWidth[ col1 ] = d->fldWidth[ col2 ]; + + d->fld[ col2 ] = fld; + d->fldLabel[ col2 ] = fldLabel; + d->fldIcon[ col2 ] = fldIcon; + d->fldWidth[ col2 ] = fldWidth; + + int colIndex = d->colIndex[ col1 ]; + d->colIndex[ col1 ] = d->colIndex[ col2 ]; + d->colIndex[ col2 ] = colIndex; +} + +/*! + \reimp +*/ + +void QDataTable::drawContents( QPainter * p, int cx, int cy, int cw, int ch ) +{ + QTable::drawContents( p, cx, cy, cw, ch ); + if ( sqlCursor() && currentRow() >= 0 ) + sqlCursor()->seek( currentRow() ); +} + +/*! + \reimp +*/ + +void QDataTable::hideColumn( int col ) +{ + d->fldHidden[col] = TRUE; + refresh( RefreshColumns ); +} + +/*! + \reimp +*/ + +void QDataTable::showColumn( int col ) +{ + d->fldHidden[col] = FALSE; + refresh( RefreshColumns ); +} + +/*! + \fn void QDataTable::currentChanged( QSqlRecord* record ) + + This signal is emitted whenever a new row is selected in the + table. The \a record parameter points to the contents of the newly + selected record. +*/ + +/*! + \fn void QDataTable::primeInsert( QSqlRecord* buf ) + + This signal is emitted after the cursor is primed for insert by + the table, when an insert action is beginning on the table. The \a + buf parameter points to the edit buffer being inserted. Connect to + this signal in order to, for example, prime the record buffer with + default data values. +*/ + +/*! + \fn void QDataTable::primeUpdate( QSqlRecord* buf ) + + This signal is emitted after the cursor is primed for update by + the table, when an update action is beginning on the table. The \a + buf parameter points to the edit buffer being updated. Connect to + this signal in order to, for example, provide some visual feedback + that the user is in 'edit mode'. +*/ + +/*! + \fn void QDataTable::primeDelete( QSqlRecord* buf ) + + This signal is emitted after the cursor is primed for delete by + the table, when a delete action is beginning on the table. The \a + buf parameter points to the edit buffer being deleted. Connect to + this signal in order to, for example, record auditing information + on deletions. +*/ + +/*! + \fn void QDataTable::beforeInsert( QSqlRecord* buf ) + + This signal is emitted just before the cursor's edit buffer is + inserted into the database. The \a buf parameter points to the + edit buffer being inserted. Connect to this signal to, for + example, populate a key field with a unique sequence number. +*/ + +/*! + \fn void QDataTable::beforeUpdate( QSqlRecord* buf ) + + This signal is emitted just before the cursor's edit buffer is + updated in the database. The \a buf parameter points to the edit + buffer being updated. Connect to this signal when you want to + transform the user's data behind-the-scenes. +*/ + +/*! + \fn void QDataTable::beforeDelete( QSqlRecord* buf ) + + This signal is emitted just before the currently selected record + is deleted from the database. The \a buf parameter points to the + edit buffer being deleted. Connect to this signal to, for example, + copy some of the fields for later use. +*/ + +/*! + \fn void QDataTable::cursorChanged( QSql::Op mode ) + + This signal is emitted whenever the cursor record was changed due + to an edit. The \a mode parameter is the type of edit that just + took place. +*/ + +#endif diff --git a/main/dependencies/qt3/src/sql/qdatatable.h b/main/dependencies/qt3/src/sql/qdatatable.h new file mode 100644 index 000000000..5d3bed190 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qdatatable.h @@ -0,0 +1,244 @@ +/**************************************************************************** +** +** Definition of QDataTable class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QDATATABLE_H +#define QDATATABLE_H + +#ifndef QT_H +#include "qstring.h" +#include "qvariant.h" +#include "qtable.h" +#include "qsql.h" +#include "qsqlcursor.h" +#include "qsqlindex.h" +#include "qsqleditorfactory.h" +#include "qiconset.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL_VIEW_WIDGETS + +class QPainter; +class QSqlField; +class QSqlPropertyMap; +class QDataTablePrivate; + +class QM_EXPORT_SQL QDataTable : public QTable +{ + Q_OBJECT + + Q_PROPERTY( QString nullText READ nullText WRITE setNullText ) + Q_PROPERTY( QString trueText READ trueText WRITE setTrueText ) + Q_PROPERTY( QString falseText READ falseText WRITE setFalseText ) + Q_PROPERTY( DateFormat dateFormat READ dateFormat WRITE setDateFormat ) + Q_PROPERTY( bool confirmEdits READ confirmEdits WRITE setConfirmEdits ) + Q_PROPERTY( bool confirmInsert READ confirmInsert WRITE setConfirmInsert ) + Q_PROPERTY( bool confirmUpdate READ confirmUpdate WRITE setConfirmUpdate ) + Q_PROPERTY( bool confirmDelete READ confirmDelete WRITE setConfirmDelete ) + Q_PROPERTY( bool confirmCancels READ confirmCancels WRITE setConfirmCancels ) + Q_PROPERTY( bool autoEdit READ autoEdit WRITE setAutoEdit ) + Q_PROPERTY( QString filter READ filter WRITE setFilter ) + Q_PROPERTY( QStringList sort READ sort WRITE setSort ) + Q_PROPERTY( int numCols READ numCols ) + Q_PROPERTY( int numRows READ numRows ) + +public: + QDataTable ( QWidget* parent=0, const char* name=0 ); + QDataTable ( QSqlCursor* cursor, bool autoPopulate = FALSE, QWidget* parent=0, const char* name=0 ); + ~QDataTable(); + + virtual void addColumn( const QString& fieldName, + const QString& label = QString::null, + int width = -1, + const QIconSet& iconset = QIconSet() ); + virtual void removeColumn( uint col ); + virtual void setColumn( uint col, const QString& fieldName, + const QString& label = QString::null, + int width = -1, + const QIconSet& iconset = QIconSet() ); + + QString nullText() const; + QString trueText() const; + QString falseText() const; + DateFormat dateFormat() const; + bool confirmEdits() const; + bool confirmInsert() const; + bool confirmUpdate() const; + bool confirmDelete() const; + bool confirmCancels() const; + bool autoDelete() const; + bool autoEdit() const; + QString filter() const; + QStringList sort() const; + + virtual void setSqlCursor( QSqlCursor* cursor = 0, + bool autoPopulate = FALSE, bool autoDelete = FALSE ); + QSqlCursor* sqlCursor() const; + + virtual void setNullText( const QString& nullText ); + virtual void setTrueText( const QString& trueText ); + virtual void setFalseText( const QString& falseText ); + virtual void setDateFormat( const DateFormat f ); + virtual void setConfirmEdits( bool confirm ); + virtual void setConfirmInsert( bool confirm ); + virtual void setConfirmUpdate( bool confirm ); + virtual void setConfirmDelete( bool confirm ); + virtual void setConfirmCancels( bool confirm ); + virtual void setAutoDelete( bool enable ); + virtual void setAutoEdit( bool autoEdit ); + virtual void setFilter( const QString& filter ); + virtual void setSort( const QStringList& sort ); + virtual void setSort( const QSqlIndex& sort ); + + enum Refresh { + RefreshData = 1, + RefreshColumns = 2, + RefreshAll = 3 + }; + void refresh( Refresh mode ); + void sortColumn ( int col, bool ascending = TRUE, + bool wholeRows = FALSE ); + QString text ( int row, int col ) const; + QVariant value ( int row, int col ) const; + QSqlRecord* currentRecord() const; + + void installEditorFactory( QSqlEditorFactory * f ); + void installPropertyMap( QSqlPropertyMap* m ); + + int numCols() const; + int numRows() const; + void setNumCols( int c ); + void setNumRows ( int r ); + bool findBuffer( const QSqlIndex& idx, int atHint = 0 ); + + void hideColumn( int col ); + void showColumn( int col ); +signals: + void currentChanged( QSqlRecord* record ); + void primeInsert( QSqlRecord* buf ); + void primeUpdate( QSqlRecord* buf ); + void primeDelete( QSqlRecord* buf ); + void beforeInsert( QSqlRecord* buf ); + void beforeUpdate( QSqlRecord* buf ); + void beforeDelete( QSqlRecord* buf ); + void cursorChanged( QSql::Op mode ); + +public slots: + virtual void find( const QString & str, bool caseSensitive, + bool backwards ); + virtual void sortAscending( int col ); + virtual void sortDescending( int col ); + virtual void refresh(); + void setColumnWidth( int col, int w ); + void adjustColumn( int col ); + void setColumnStretchable( int col, bool stretch ); + void swapColumns( int col1, int col2, bool swapHeaders = FALSE ); + +protected: + virtual bool insertCurrent(); + virtual bool updateCurrent(); + virtual bool deleteCurrent(); + + virtual QSql::Confirm confirmEdit( QSql::Op m ); + virtual QSql::Confirm confirmCancel( QSql::Op m ); + + virtual void handleError( const QSqlError& e ); + + virtual bool beginInsert(); + virtual QWidget* beginUpdate ( int row, int col, bool replace ); + + bool eventFilter( QObject *o, QEvent *e ); + void keyPressEvent( QKeyEvent* ); + void resizeEvent ( QResizeEvent * ); + void contentsMousePressEvent( QMouseEvent* e ); + void contentsContextMenuEvent( QContextMenuEvent* e ); + void endEdit( int row, int col, bool accept, bool replace ); + QWidget * createEditor( int row, int col, bool initFromCell ) const; + void activateNextCell(); + int indexOf( uint i ) const; // ### make this public in 4.0 + void reset(); + void setSize( QSqlCursor* sql ); + void repaintCell( int row, int col ); + void paintCell ( QPainter * p, int row, int col, const QRect & cr, + bool selected, const QColorGroup &cg ); + virtual void paintField( QPainter * p, const QSqlField* field, const QRect & cr, + bool selected ); + void drawContents( QPainter * p, int cx, int cy, int cw, int ch ); + virtual int fieldAlignment( const QSqlField* field ); + void columnClicked ( int col ); + void resizeData ( int len ); + + QTableItem * item ( int row, int col ) const; + void setItem ( int row, int col, QTableItem * item ); + void clearCell ( int row, int col ) ; + void setPixmap ( int row, int col, const QPixmap & pix ); + void takeItem ( QTableItem * i ); + +private slots: + void loadNextPage(); + void setCurrentSelection( int row, int col ); + void updateCurrentSelection(); + void sliderPressed(); + void sliderReleased(); + void doInsertCurrent(); + void doUpdateCurrent(); + +private: + QString fieldToString( const QSqlField * field ); + void init(); + QWidget* beginEdit ( int row, int col, bool replace ); + void updateRow( int row ); + void endInsert(); + void endUpdate(); + QDataTablePrivate* d; + +#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator= + QDataTable( const QDataTable & ); + QDataTable &operator=( const QDataTable & ); +#endif +}; + +#endif +#endif diff --git a/main/dependencies/qt3/src/sql/qdataview.cpp b/main/dependencies/qt3/src/sql/qdataview.cpp new file mode 100644 index 000000000..ceafe091a --- /dev/null +++ b/main/dependencies/qt3/src/sql/qdataview.cpp @@ -0,0 +1,208 @@ +/**************************************************************************** +** +** Implementation of QDataView class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qdataview.h" + +#ifndef QT_NO_SQL_VIEW_WIDGETS + +#include "qsqlmanager_p.h" + +class QDataViewPrivate +{ +public: + QDataViewPrivate() {} + QSqlFormManager frm; +}; + + +/*! + \class QDataView qdataview.h + \brief The QDataView class provides read-only SQL forms. + + \ingroup database + \mainclass + \module sql + + This class provides a form which displays SQL field data from a + record buffer. Because QDataView does not support editing it uses + less resources than a QDataBrowser. This class is well suited for + displaying read-only data from a SQL database. + + If you want a to present your data in an editable form use + QDataBrowser; if you want a table-based presentation of your data + use QDataTable. + + The form is associated with the data view with setForm() and the + record is associated with setRecord(). You can also pass a + QSqlRecord to the refresh() function which will set the record to + the given record and read the record's fields into the form. +*/ + +/*! + Constructs a data view which is a child of \a parent, called \a + name, and with widget flags \a fl. +*/ + +QDataView::QDataView( QWidget *parent, const char *name, WFlags fl ) + : QWidget( parent, name, fl ) +{ + d = new QDataViewPrivate(); +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QDataView::~QDataView() +{ + delete d; +} + +/*! + Clears the default form's values. If there is no default form, + nothing happens. All the values are set to their 'zero state', + e.g. 0 for numeric fields, "" for string fields. +*/ + +void QDataView::clearValues() +{ + d->frm.clearValues(); +} + +/*! + Sets the form used by the data view to \a form. If a record has + already been assigned to the data view, the form will display that + record's data. + + \sa form() +*/ + +void QDataView::setForm( QSqlForm* form ) +{ + d->frm.setForm( form ); +} + + +/*! + Returns the default form used by the data view, or 0 if there is + none. + + \sa setForm() +*/ + +QSqlForm* QDataView::form() +{ + return d->frm.form(); +} + + +/*! + Sets the record used by the data view to \a record. If a form has + already been assigned to the data view, the form will display the + data from \a record in that form. + + \sa record() +*/ + +void QDataView::setRecord( QSqlRecord* record ) +{ + d->frm.setRecord( record ); +} + + +/*! + Returns the default record used by the data view, or 0 if there is + none. + + \sa setRecord() +*/ + +QSqlRecord* QDataView::record() +{ + return d->frm.record(); +} + + +/*! + Causes the default form to read its fields from the record buffer. + If there is no default form, or no record, nothing happens. + + \sa setForm() +*/ + +void QDataView::readFields() +{ + d->frm.readFields(); +} + +/*! + Causes the default form to write its fields to the record buffer. + If there is no default form, or no record, nothing happens. + + \sa setForm() +*/ + +void QDataView::writeFields() +{ + d->frm.writeFields(); +} + +/*! + Causes the default form to display the contents of \a buf. If + there is no default form, nothing happens.The \a buf also becomes + the default record for all subsequent calls to readFields() and + writefields(). This slot is equivalant to calling: + + \code + myView.setRecord( record ); + myView.readFields(); + \endcode + + \sa setRecord() readFields() +*/ + +void QDataView::refresh( QSqlRecord* buf ) +{ + if ( buf && buf != record() ) + setRecord( buf ); + readFields(); +} + +#endif diff --git a/main/dependencies/qt3/src/sql/qdataview.h b/main/dependencies/qt3/src/sql/qdataview.h new file mode 100644 index 000000000..cd1cf9251 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qdataview.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Definition of QDataView class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QDATAVIEW_H +#define QDATAVIEW_H + +#ifndef QT_H +#include "qwidget.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL_VIEW_WIDGETS + +class QSqlForm; +class QSqlRecord; +class QDataViewPrivate; + +class QM_EXPORT_SQL QDataView : public QWidget +{ + Q_OBJECT + +public: + QDataView( QWidget* parent=0, const char* name=0, WFlags fl = 0 ); + ~QDataView(); + + virtual void setForm( QSqlForm* form ); + QSqlForm* form(); + virtual void setRecord( QSqlRecord* record ); + QSqlRecord* record(); + +public slots: + virtual void refresh( QSqlRecord* buf ); + virtual void readFields(); + virtual void writeFields(); + virtual void clearValues(); + +private: + QDataViewPrivate* d; + +#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator= + QDataView( const QDataView & ); + QDataView &operator=( const QDataView & ); +#endif +}; + + +#endif +#endif diff --git a/main/dependencies/qt3/src/sql/qeditorfactory.cpp b/main/dependencies/qt3/src/sql/qeditorfactory.cpp new file mode 100644 index 000000000..370f577a9 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qeditorfactory.cpp @@ -0,0 +1,192 @@ +/**************************************************************************** +** +** Implementation of QEditorFactory class +** +** Created : 2000-11-17 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qcleanuphandler.h" +#include "qlabel.h" +#include "qlineedit.h" +#include "qspinbox.h" +#include "qcombobox.h" + +#include "qeditorfactory.h" +#include "qdatetimeedit.h" + +#ifndef QT_NO_SQL_EDIT_WIDGETS + +/*! + \class QEditorFactory qeditorfactory.h + \brief The QEditorFactory class is used to create editor widgets + for QVariant data types. + + \ingroup database + \module sql + + Each editor factory provides the createEditor() function which + given a QVariant will create and return a QWidget that can edit + that QVariant. For example if you have a QVariant::String type, a + QLineEdit would be the default editor returned, whereas a + QVariant::Int's default editor would be a QSpinBox. + + If you want to create different editors for fields with the same + data type, subclass QEditorFactory and reimplement the + createEditor() function. +*/ + +/*! + Constructs an editor factory with parent \a parent, called \a name. +*/ + +QEditorFactory::QEditorFactory ( QObject * parent, const char * name ) + : QObject( parent, name ) +{ + +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QEditorFactory::~QEditorFactory() +{ + +} + +static QEditorFactory * defaultfactory = 0; +static QCleanupHandler< QEditorFactory > q_cleanup_editor_factory; + +/*! + Returns an instance of a default editor factory. +*/ + +QEditorFactory * QEditorFactory::defaultFactory() +{ + if( defaultfactory == 0 ){ + defaultfactory = new QEditorFactory(); + q_cleanup_editor_factory.add( &defaultfactory ); + } + + return defaultfactory; +} + +/*! + Replaces the default editor factory with \a factory. + \e{QEditorFactory takes ownership of factory, and destroys it + when it is no longer needed.} +*/ + +void QEditorFactory::installDefaultFactory( QEditorFactory * factory ) +{ + if( factory == 0 || factory == defaultfactory ) return; + + if( defaultfactory != 0 ){ + q_cleanup_editor_factory.remove( &defaultfactory ); + delete defaultfactory; + } + defaultfactory = factory; + q_cleanup_editor_factory.add( &defaultfactory ); +} + +/*! + Creates and returns the appropriate editor for the QVariant \a v. + If the QVariant is invalid, 0 is returned. The \a parent is passed + to the appropriate editor's constructor. +*/ + +QWidget * QEditorFactory::createEditor( QWidget * parent, const QVariant & v ) +{ + QWidget * w = 0; + switch( v.type() ){ + case QVariant::Invalid: + w = 0; + break; + case QVariant::Bool: + w = new QComboBox( parent, "qt_editor_bool" ); + ((QComboBox *) w)->insertItem( "False" ); + ((QComboBox *) w)->insertItem( "True" ); + break; + case QVariant::UInt: + w = new QSpinBox( 0, 999999, 1, parent, "qt_editor_spinbox" ); + break; + case QVariant::Int: + w = new QSpinBox( -999999, 999999, 1, parent, "qt_editor_int" ); + break; + case QVariant::String: + case QVariant::CString: + case QVariant::Double: + w = new QLineEdit( parent, "qt_editor_double" ); + ((QLineEdit*)w)->setFrame( FALSE ); + break; + case QVariant::Date: + w = new QDateEdit( parent, "qt_editor_date" ); + break; + case QVariant::Time: + w = new QTimeEdit( parent, "qt_editor_time" ); + break; + case QVariant::DateTime: + w = new QDateTimeEdit( parent, "qt_editor_datetime" ); + break; +#ifndef QT_NO_LABEL + case QVariant::Pixmap: + w = new QLabel( parent, "qt_editor_pixmap" ); + break; +#endif + case QVariant::Palette: + case QVariant::ColorGroup: + case QVariant::Color: + case QVariant::Font: + case QVariant::Brush: + case QVariant::Bitmap: + case QVariant::Cursor: + case QVariant::Map: + case QVariant::StringList: + case QVariant::Rect: + case QVariant::Size: + case QVariant::IconSet: + case QVariant::Point: + case QVariant::PointArray: + case QVariant::Region: + case QVariant::SizePolicy: + case QVariant::ByteArray: + default: + w = new QWidget( parent, "qt_editor_default" ); + break; + } + return w; +} +#endif // QT_NO_SQL diff --git a/main/dependencies/qt3/src/sql/qeditorfactory.h b/main/dependencies/qt3/src/sql/qeditorfactory.h new file mode 100644 index 000000000..8a0fb9112 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qeditorfactory.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Definition of QEditorFactory class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QEDITORFACTORY_H +#define QEDITORFACTORY_H + +#ifndef QT_H +#include "qobject.h" +#include "qvariant.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL_EDIT_WIDGETS + +class QM_EXPORT_SQL QEditorFactory : public QObject +{ +public: + QEditorFactory ( QObject * parent = 0, const char * name = 0 ); + ~QEditorFactory(); + + virtual QWidget * createEditor( QWidget * parent, const QVariant & v ); + + static QEditorFactory * defaultFactory(); + static void installDefaultFactory( QEditorFactory * factory); + +private: +#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator= + QEditorFactory( const QEditorFactory & ); + QEditorFactory &operator=( const QEditorFactory & ); +#endif +}; + +#endif // QT_NO_SQL +#endif // QEDITORFACTORY_H diff --git a/main/dependencies/qt3/src/sql/qsql.cpp b/main/dependencies/qt3/src/sql/qsql.cpp new file mode 100644 index 000000000..3bf97ae13 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsql.cpp @@ -0,0 +1,114 @@ +/**************************************************************************** +** +** Implementation of QSql class +** +** Created : 2000-11-03 +** +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + + +/*! + \class QSql qsql.h + \brief The QSql class is a namespace for Qt SQL identifiers that + need to be global-like. + + \ingroup database + \mainclass + \module sql + + Normally, you can ignore this class. Several Qt SQL classes + inherit it, so all the identifiers in the Qt SQL namespace are + visible without qualification. +*/ + +/*! + \enum QSql::Confirm + + This enum type describes edit confirmations. + + \value Yes + \value No + \value Cancel +*/ + +/*! + \enum QSql::Op + + This enum type describes edit operations. + + \value None + \value Insert + \value Update + \value Delete +*/ + + +/*! + \enum QSql::Location + + This enum type describes SQL navigation locations. + + \value BeforeFirst + \value AfterLast +*/ + +/*! + \enum QSql::ParameterType + + This enum is used to set 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. +*/ + +/*! + \enum QSql::TableType + + This enum type describes types of tables + + \value Tables All the tables visible to the user + \value SystemTables Internal tables used by the DBMS + \value Views All the views visible to the user + \value AllTables All of the above +*/ + +/*! + \fn QSql::QSql() + + Constructs a Qt SQL namespace class +*/ diff --git a/main/dependencies/qt3/src/sql/qsql.h b/main/dependencies/qt3/src/sql/qsql.h new file mode 100644 index 000000000..3d4dc6f4b --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsql.h @@ -0,0 +1,100 @@ +/**************************************************************************** +** +** Definition of QSql class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQL_H +#define QSQL_H + +#ifndef QT_H +#include "qglobal.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL + +class QM_EXPORT_SQL QSql +{ +public: + QSql() {} + enum Op { + None = -1, + Insert = 0, + Update = 1, + Delete = 2 + }; + + enum Location { + BeforeFirst = -1, + AfterLast = -2 + }; + + enum Confirm { + Cancel = -1, + No = 0, + Yes = 1 + }; + + enum ParameterType { + In = 1, + Out = 2, + InOut = 3 //InOut = In | Out + }; + + enum TableType { + Tables = 0x01, + SystemTables = 0x02, + Views = 0x04, + AllTables = 0xff + }; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QSql( const QSql & ); + QSql &operator=( const QSql & ); +#endif + +}; + +#endif +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlcursor.cpp b/main/dependencies/qt3/src/sql/qsqlcursor.cpp new file mode 100644 index 000000000..a1be1f82f --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlcursor.cpp @@ -0,0 +1,1549 @@ +/**************************************************************************** +** +** Implementation of QSqlCursor class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlcursor.h" + +#ifndef QT_NO_SQL + +#include "qsqldriver.h" +#include "qsqlresult.h" +#include "qdatetime.h" +#include "qsqldatabase.h" +#include "qsql.h" + +class QSqlCursorPrivate +{ +public: + + QSqlCursorPrivate( const QString& name, QSqlDatabase* sdb ) + : lastAt( QSql::BeforeFirst ), nm( name ), srt( name ), md( 0 ), db( sdb ), q( 0 ) + {} + ~QSqlCursorPrivate() + { + delete q; + } + + QSqlQuery* query() + { + if ( !q ) + q = new QSqlQuery( 0, db ); + return q; + } + + int lastAt; + QString nm; //name + QSqlIndex srt; //sort + QString ftr; //filter + int md; //mode + QSqlIndex priIndx; //primary index + QSqlRecord editBuffer; + // the primary index as it was before the user changed the values in editBuffer + QString editIndex; + QSqlRecordInfo infoBuffer; + QSqlDatabase* db; + QSqlQuery* q; +}; + +QString qOrderByClause( const QSqlIndex & i, const QString& prefix = QString::null ) +{ + QString str; + int k = i.count(); + if( k == 0 ) return QString::null; + str = " order by " + i.toString( prefix ); + return str; +} + +QString qWhereClause( const QString& prefix, QSqlField* field, const QSqlDriver* driver ) +{ + QString f; + if ( field && driver ) { + f = ( prefix.length() > 0 ? prefix + QString(".") : QString::null ) + field->name(); + if ( field->isNull() ) { + f += " IS NULL"; + } else { + f += " = " + driver->formatValue( field ); + } + } + return f; +} + +QString qWhereClause( QSqlRecord* rec, const QString& prefix, const QString& sep, + const QSqlDriver* driver ) +{ + static QString blank( " " ); + QString filter; + bool separator = FALSE; + for ( uint j = 0; j < rec->count(); ++j ) { + QSqlField* f = rec->field( j ); + if ( rec->isGenerated( j ) ) { + if ( separator ) + filter += sep + blank; + filter += qWhereClause( prefix, f, driver ); + filter += blank; + separator = TRUE; + } + } + return filter; +} + +/*! + \class QSqlCursor qsqlcursor.h + \brief The QSqlCursor class provides browsing and editing of SQL + tables and views. + + \ingroup database + \module sql + + A QSqlCursor is a database record (see \l QSqlRecord) that + corresponds to a table or view within an SQL database (see \l + QSqlDatabase). There are two buffers in a cursor, one used for + browsing and one used for editing records. Each buffer contains a + list of fields which correspond to the fields in the table or + view. + + When positioned on a valid record, the browse buffer contains the + values of the current record's fields from the database. The edit + buffer is separate, and is used for editing existing records and + inserting new records. + + For browsing data, a cursor must first select() data from the + database. After a successful select() the cursor is active + (isActive() returns TRUE), but is initially not positioned on a + valid record (isValid() returns FALSE). To position the cursor on + a valid record, use one of the navigation functions, next(), + prev(), first(), last(), or seek(). Once positioned on a valid + record, data can be retrieved from the browse buffer using + value(). If a navigation function is not successful, it returns + FALSE, the cursor will no longer be positioned on a valid record + and the values returned by value() are undefined. + + For example: + + \quotefile sql/overview/retrieve2/main.cpp + \skipto QSqlCursor + \printline QSqlCursor + \printuntil } + + In the above example, a cursor is created specifying a table or + view name in the database. Then, select() is called, which can be + optionally parameterised to filter and order the records + retrieved. Each record in the cursor is retrieved using next(). + When next() returns FALSE, there are no more records to process, + and the loop terminates. + + For editing records (rows of data), a cursor contains a separate + edit buffer which is independent of the fields used when browsing. + The functions insert(), update() and del() operate on the edit + buffer. This allows the cursor to be repositioned to other + records while simultaneously maintaining a separate buffer for + edits. You can get a pointer to the edit buffer using + editBuffer(). The primeInsert(), primeUpdate() and primeDelete() + functions also return a pointer to the edit buffer and prepare it + for insert, update and delete respectively. Edit operations only + affect a single row at a time. Note that update() and del() + require that the table or view contain a primaryIndex() to ensure + that edit operations affect a unique record within the database. + + For example: + + \quotefile sql/overview/update/main.cpp + \skipto prices + \printline prices + \printuntil update + \printline + + To edit an existing database record, first move to the record you + wish to update. Call primeUpdate() to get the pointer to the + cursor's edit buffer. Then use this pointer to modify the values + in the edit buffer. Finally, call update() to save the changes to + the database. The values in the edit buffer will be used to + locate the appropriate record when updating the database (see + primaryIndex()). + + Similarly, when deleting an existing database record, first move + to the record you wish to delete. Then, call primeDelete() to get + the pointer to the edit buffer. Finally, call del() to delete the + record from the database. Again, the values in the edit buffer + will be used to locate and delete the appropriate record. + + To insert a new record, call primeInsert() to get the pointer to + the edit buffer. Use this pointer to populate the edit buffer + with new values and then insert() the record into the database. + + After calling insert(), update() or del(), the cursor is no longer + positioned on a valid record and can no longer be navigated + (isValid() return FALSE). The reason for this is that any changes + made to the database will not be visible until select() is called + to refresh the cursor. You can change this behavior by passing + FALSE to insert(), update() or del() which will prevent the cursor + from becoming invalid. The edits will still not be visible when + navigating the cursor until select() is called. + + QSqlCursor contains virtual methods which allow editing behavior + to be customized by subclasses. This allows custom cursors to be + created that encapsulate the editing behavior of a database table + for an entire application. For example, a cursor can be customized + to always auto-number primary index fields, or provide fields with + suitable default values, when inserting new records. QSqlCursor + generates SQL statements which are sent to the database engine; + you can control which fields are included in these statements + using setGenerated(). + + Note that QSqlCursor does not inherit from QObject. This means + that you are responsible for destroying instances of this class + yourself. However if you create a QSqlCursor and use it in a + \l QDataTable, \l QDataBrowser or a \l QDataView these classes will + usually take ownership of the cursor and destroy it when they + don't need it anymore. The documentation for QDataTable, + QDataBrowser and QDataView explicitly states which calls take + ownership of the cursor. +*/ + +/*! + \enum QSqlCursor::Mode + + This enum type describes how QSqlCursor operates on records in the + database. + + \value ReadOnly the cursor can only SELECT records from the + database. + + \value Insert the cursor can INSERT records into the database. + + \value Update the cursor can UPDATE records in the database. + + \value Delete the cursor can DELETE records from the database. + + \value Writable the cursor can INSERT, UPDATE and DELETE records + in the database. +*/ + +/*! + Constructs a cursor on database \a db using table or view \a name. + + If \a autopopulate is TRUE (the default), the \a name of the + cursor must correspond to an existing table or view name in the + database so that field information can be automatically created. + If the table or view does not exist, the cursor will not be + functional. + + The cursor is created with an initial mode of QSqlCursor::Writable + (meaning that records can be inserted, updated or deleted using + the cursor). If the cursor does not have a unique primary index, + update and deletes cannot be performed. + + Note that \a autopopulate refers to populating the cursor with + meta-data, e.g. the names of the table's fields, not with + retrieving data. The select() function is used to populate the + cursor with data. + + \sa setName() setMode() +*/ + +QSqlCursor::QSqlCursor( const QString & name, bool autopopulate, QSqlDatabase* db ) + : QSqlRecord(), QSqlQuery( QString::null, db ) +{ + d = new QSqlCursorPrivate( name, db ); + setMode( Writable ); + if ( !d->nm.isNull() ) + setName( d->nm, autopopulate ); +} + +/*! + Constructs a copy of \a other. +*/ + +QSqlCursor::QSqlCursor( const QSqlCursor & other ) + : QSqlRecord( other ), QSqlQuery( other ) +{ + d = new QSqlCursorPrivate( other.d->nm, other.d->db ); + d->lastAt = other.d->lastAt; + d->nm = other.d->nm; + d->srt = other.d->srt; + d->ftr = other.d->ftr; + d->priIndx = other.d->priIndx; + d->editBuffer = other.d->editBuffer; + d->infoBuffer = other.d->infoBuffer; + d->q = 0; // do not share queries + setMode( other.mode() ); +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QSqlCursor::~QSqlCursor() +{ + delete d; +} + +/*! + Sets the cursor equal to \a other. +*/ + +QSqlCursor& QSqlCursor::operator=( const QSqlCursor& other ) +{ + QSqlRecord::operator=( other ); + QSqlQuery::operator=( other ); + delete d; + d = new QSqlCursorPrivate( other.d->nm, other.d->db ); + d->lastAt = other.d->lastAt; + d->nm = other.d->nm; + d->srt = other.d->srt; + d->ftr = other.d->ftr; + d->priIndx = other.d->priIndx; + d->editBuffer = other.d->editBuffer; + d->infoBuffer = other.d->infoBuffer; + d->q = 0; // do not share queries + setMode( other.mode() ); + return *this; +} + +/*! + Sets the current sort to \a sort. Note that no new records are + selected. To select new records, use select(). The \a sort will + apply to any subsequent select() calls that do not explicitly + specify a sort. +*/ + +void QSqlCursor::setSort( const QSqlIndex& sort ) +{ + d->srt = sort; +} + +/*! + Returns the current sort, or an empty index if there is no current + sort. +*/ +QSqlIndex QSqlCursor::sort() const +{ + return d->srt; +} + +/*! + Sets the current filter to \a filter. Note that no new records are + selected. To select new records, use select(). The \a filter will + apply to any subsequent select() calls that do not explicitly + specify a filter. + + The filter is a SQL \c WHERE clause without the keyword 'WHERE', + e.g. \c{name='Dave'} which will be processed by the DBMS. +*/ +void QSqlCursor::setFilter( const QString& filter ) +{ + d->ftr = filter; +} + +/*! + Returns the current filter, or an empty string if there is no + current filter. +*/ +QString QSqlCursor::filter() const +{ + return d->ftr; +} + +/*! + Sets the name of the cursor to \a name. If \a autopopulate is TRUE + (the default), the \a name must correspond to a valid table or + view name in the database. Also, note that all references to the + cursor edit buffer become invalidated when fields are + auto-populated. See the QSqlCursor constructor documentation for + more information. +*/ +void QSqlCursor::setName( const QString& name, bool autopopulate ) +{ + d->nm = name; + if ( autopopulate ) { + if ( driver() ) { + d->infoBuffer = driver()->recordInfo( name ); + *this = d->infoBuffer.toRecord(); + d->editBuffer = *this; + d->priIndx = driver()->primaryIndex( name ); + } +#ifdef QT_CHECK_RANGE + if ( isEmpty() ) + qWarning("QSqlCursor::setName: unable to build record, does '%s' exist?", name.latin1() ); +#endif + } +} + +/*! + Returns the name of the cursor. +*/ + +QString QSqlCursor::name() const +{ + return d->nm; +} + +/*! \reimp +*/ + +QString QSqlCursor::toString( const QString& prefix, const QString& sep ) const +{ + QString pflist; + QString pfix = prefix.isEmpty() ? QString::null : prefix + "."; + bool comma = FALSE; + + for ( uint i = 0; i < count(); ++i ) { + const QString fname = fieldName( i ); + if ( isGenerated( i ) ) { + if( comma ) + pflist += sep + " "; + pflist += pfix + fname; + comma = TRUE; + } + } + return pflist; +} + +/*! + \internal + + Assigns the record \a list. + +*/ +QSqlRecord & QSqlCursor::operator=( const QSqlRecord & list ) +{ + return QSqlRecord::operator=( list ); +} + +/*! + Append a copy of field \a fieldInfo to the end of the cursor. Note + that all references to the cursor edit buffer become invalidated. +*/ + +void QSqlCursor::append( const QSqlFieldInfo& fieldInfo ) +{ + d->editBuffer.append( fieldInfo.toField() ); + d->editBuffer.setGenerated( d->editBuffer.count() - 1, fieldInfo.isGenerated() ); + d->infoBuffer.append( fieldInfo ); + QSqlRecord::append( fieldInfo.toField() ); + QSqlRecord::setGenerated( QSqlRecord::count() - 1, fieldInfo.isGenerated() ); +} + +/*! + Removes all fields from the cursor. Note that all references to + the cursor edit buffer become invalidated. +*/ +void QSqlCursor::clear() +{ + d->editBuffer.clear(); + d->infoBuffer.clear(); + QSqlRecord::clear(); +} + + +/*! + Insert a copy of \a fieldInfo at position \a pos. If a field + already exists at \a pos, it is removed. Note that all references + to the cursor edit buffer become invalidated. +*/ + +void QSqlCursor::insert( int pos, const QSqlFieldInfo& fieldInfo ) +{ + d->editBuffer.insert( pos, fieldInfo.toField() ); + d->editBuffer.setGenerated( pos, fieldInfo.isGenerated() ); + d->infoBuffer[ pos ] = fieldInfo; + QSqlRecord::insert( pos, fieldInfo.toField() ); + QSqlRecord::setGenerated( pos, fieldInfo.isGenerated() ); +} + +/*! + Removes the field at \a pos. If \a pos does not exist, nothing + happens. Note that all references to the cursor edit buffer become + invalidated. +*/ + +void QSqlCursor::remove( int pos ) +{ + d->editBuffer.remove( pos ); + d->infoBuffer[ pos ] = QSqlFieldInfo(); + QSqlRecord::remove( pos ); +} + +/*! + Sets the generated flag for the field \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 insert(), update() or del(). + + \sa isGenerated() +*/ + +void QSqlCursor::setGenerated( const QString& name, bool generated ) +{ + int pos = position( name ); + if ( pos == -1 ) + return; + QSqlRecord::setGenerated( name, generated ); + d->editBuffer.setGenerated( name, generated ); + d->infoBuffer[ pos ].setGenerated( generated ); +} + +/*! + \overload + + Sets the generated flag for the field \a i to \a generated. + + \sa isGenerated() +*/ +void QSqlCursor::setGenerated( int i, bool generated ) +{ + if ( i < 0 || i >= (int)d->infoBuffer.count() ) + return; + QSqlRecord::setGenerated( i, generated ); + d->editBuffer.setGenerated( i, generated ); + d->infoBuffer[i].setGenerated( generated ); +} + +/*! + Returns the primary index associated with the cursor as defined in + the database, or an empty index if there is no primary index. If + \a setFromCursor is TRUE (the default), the index fields are + populated with the corresponding values in the cursor's current + record. +*/ + +QSqlIndex QSqlCursor::primaryIndex( bool setFromCursor ) const +{ + if ( setFromCursor ) { + for ( uint i = 0; i < d->priIndx.count(); ++i ) { + const QString fn = d->priIndx.fieldName( i ); + if ( contains( fn ) ) + d->priIndx.setValue( i, value( fn ) ); + } + } + return d->priIndx; +} + +/*! + Sets the primary index associated with the cursor to the index \a + idx. Note that this index must contain a field or set of fields + which identify a unique record within the underlying database + table or view so that update() and del() will execute as expected. + + \sa update() del() +*/ + +void QSqlCursor::setPrimaryIndex( const QSqlIndex& idx ) +{ + d->priIndx = idx; +} + + +/*! + Returns an index composed of \a fieldNames, all in ASCending + order. Note that all field names must exist in the cursor, + otherwise an empty index is returned. + + \sa QSqlIndex +*/ + +QSqlIndex QSqlCursor::index( const QStringList& fieldNames ) const +{ + QSqlIndex idx; + for ( QStringList::ConstIterator it = fieldNames.begin(); it != fieldNames.end(); ++it ) { + const QSqlField* f = field( (*it) ); + if ( !f ) { /* all fields must exist */ + idx.clear(); + break; + } + idx.append( *f ); + } + return idx; +} + +/*! + \overload + + Returns an index based on \a fieldName. +*/ + +QSqlIndex QSqlCursor::index( const QString& fieldName ) const +{ + QStringList fl( fieldName ); + return index( fl ); +} + +/*! + \overload + + Returns an index based on \a fieldName. +*/ + +QSqlIndex QSqlCursor::index( const char* fieldName ) const +{ + return index( QStringList( QString( fieldName ) ) ); +} + +/*! + Selects all fields in the cursor from the database matching the + filter criteria \a filter. The data is returned in the order + specified by the index \a sort. Returns TRUE if the data was + successfully selected; otherwise returns FALSE. + + The \a filter is a string containing a SQL \c WHERE clause but + without the 'WHERE' keyword. The cursor is initially positioned at + an invalid row after this function is called. To move to a valid + row, use seek(), first(), last(), prev() or next(). + + Example: + \code + QSqlCursor cur( "Employee" ); // Use the Employee table or view + cur.select( "deptno=10" ); // select all records in department 10 + while( cur.next() ) { + ... // process data + } + ... + // select records in other departments, ordered by department number + cur.select( "deptno>10", cur.index( "deptno" ) ); + ... + \endcode + + The filter will apply to any subsequent select() calls that do not + explicitly specify another filter. Similarly the sort will apply + to any subsequent select() calls that do not explicitly specify + another sort. + + \code + QSqlCursor cur( "Employee" ); + cur.select( "deptno=10" ); // select all records in department 10 + while( cur.next() ) { + ... // process data + } + ... + cur.select(); // re-selects all records in department 10 + ... + \endcode + +*/ + +bool QSqlCursor::select( const QString & filter, const QSqlIndex & sort ) +{ + QString fieldList = toString( d->nm ); + if ( fieldList.isEmpty() ) + return FALSE; + QString str= "select " + fieldList; + str += " from " + d->nm; + if ( !filter.isEmpty() ) { + d->ftr = filter; + str += " where " + filter; + } else + d->ftr = QString::null; + if ( sort.count() > 0 ) + str += " order by " + sort.toString( d->nm ); + d->srt = sort; + return exec( str ); +} + +/*! + \overload + + Selects all fields in the cursor from the database. The rows are + returned in the order specified by the last call to setSort() or + the last call to select() that specified a sort, whichever is the + most recent. If there is no current sort, the order in which the + rows are returned is undefined. The records are filtered according + to the filter specified by the last call to setFilter() or the + last call to select() that specified a filter, whichever is the + most recent. If there is no current filter, all records are + returned. The cursor is initially positioned at an invalid row. To + move to a valid row, use seek(), first(), last(), prev() or + next(). + + \sa setSort() setFilter() +*/ + +bool QSqlCursor::select() +{ + return select( filter(), sort() ); +} + +/*! + \overload + + Selects all fields in the cursor from the database. The data is + returned in the order specified by the index \a sort. The records + are filtered according to the filter specified by the last call to + setFilter() or the last call to select() that specified a filter, + whichever is the most recent. The cursor is initially positioned + at an invalid row. To move to a valid row, use seek(), first(), + last(), prev() or next(). +*/ + +bool QSqlCursor::select( const QSqlIndex& sort ) +{ + return select( filter(), sort ); +} + +/*! + \overload + + Selects all fields in the cursor matching the filter index \a + filter. The data is returned in the order specified by the index + \a sort. The \a filter index works by constructing a WHERE clause + using the names of the fields from the \a filter and their values + from the current cursor record. The cursor is initially positioned + at an invalid row. To move to a valid row, use seek(), first(), + last(), prev() or next(). This function is useful, for example, + for retrieving data based upon a table's primary index: + + \code + QSqlCursor cur( "Employee" ); + QSqlIndex pk = cur.primaryIndex(); + cur.setValue( "id", 10 ); + cur.select( pk, pk ); // generates "SELECT ... FROM Employee WHERE id=10 ORDER BY id" + ... + \endcode + + In this example the QSqlIndex, pk, is used for two different + purposes. When used as the filter (first) argument, the field + names it contains are used to construct the WHERE clause, each set + to the current cursor value, \c{WHERE id=10}, in this case. When + used as the sort (second) argument the field names it contains are + used for the ORDER BY clause, \c{ORDER BY id} in this example. +*/ + +bool QSqlCursor::select( const QSqlIndex & filter, const QSqlIndex & sort ) +{ + return select( toString( filter, this, d->nm, "=", "and" ), sort ); +} + +/*! + Sets the cursor mode to \a mode. This value can be an OR'ed + combination of \l QSqlCursor::Mode values. The default mode for a + cursor is \c QSqlCursor::Writable. + + \code + QSqlCursor cur( "Employee" ); + cur.setMode( QSqlCursor::Writable ); // allow insert/update/delete + ... + cur.setMode( QSqlCursor::Insert | QSqlCursor::Update ); // allow inserts and updates only + ... + cur.setMode( QSqlCursor::ReadOnly ); // no inserts/updates/deletes allowed + + \endcode +*/ + +void QSqlCursor::setMode( int mode ) +{ + d->md = mode; +} + +/*! + Returns the current cursor mode. + + \sa setMode() +*/ + +int QSqlCursor::mode() const +{ + return d->md; +} + +/*! + Sets field \a name to \a calculated. If the field \a name does not + exist, nothing happens. The value of a calculated field is set by + the calculateField() virtual function which you must reimplement + (or the field value will be an invalid QVariant). Calculated + fields do not appear in generated SQL statements sent to the + database. + + \sa calculateField() QSqlRecord::setGenerated() +*/ + +void QSqlCursor::setCalculated( const QString& name, bool calculated ) +{ + int pos = position( name ); + if ( pos < 0 ) + return; + d->infoBuffer[ pos ].setCalculated( calculated ); + if ( calculated ) + setGenerated( pos, FALSE ); +} + +/*! + Returns TRUE if the field \a name exists and is calculated; + otherwise returns FALSE. + + \sa setCalculated() +*/ + +bool QSqlCursor::isCalculated( const QString& name ) const +{ + int pos = position( name ); + if ( pos < 0 ) + return FALSE; + return d->infoBuffer[ pos ].isCalculated(); +} + +/*! + Sets field \a{name}'s trimmed status to \a trim. If the field \a + name does not exist, nothing happens. + + When a trimmed field of type string or cstring is read from the + database any trailing (right-most) spaces are removed. + + \sa isTrimmed() QVariant +*/ + +void QSqlCursor::setTrimmed( const QString& name, bool trim ) +{ + int pos = position( name ); + if ( pos < 0 ) + return; + d->infoBuffer[ pos ].setTrim( trim ); +} + +/*! + Returns TRUE if the field \a name exists and is trimmed; otherwise + returns FALSE. + + When a trimmed field of type string or cstring is read from the + database any trailing (right-most) spaces are removed. + + \sa setTrimmed() +*/ + +bool QSqlCursor::isTrimmed( const QString& name ) const +{ + int pos = position( name ); + if ( pos < 0 ) + return FALSE; + return d->infoBuffer[ pos ].isTrim(); +} + +/*! + Returns TRUE if the cursor is read-only; otherwise returns FALSE. + The default is FALSE. Read-only cursors cannot be edited using + insert(), update() or del(). + + \sa setMode() +*/ + +bool QSqlCursor::isReadOnly() const +{ + return d->md == 0; +} + +/*! + Returns TRUE if the cursor will perform inserts; otherwise returns + FALSE. + + \sa setMode() +*/ + +bool QSqlCursor::canInsert() const +{ + return ( ( d->md & Insert ) == Insert ) ; +} + + +/*! + Returns TRUE if the cursor will perform updates; otherwise returns + FALSE. + + \sa setMode() +*/ + +bool QSqlCursor::canUpdate() const +{ + return ( ( d->md & Update ) == Update ) ; +} + +/*! + Returns TRUE if the cursor will perform deletes; otherwise returns + FALSE. + + \sa setMode() +*/ + +bool QSqlCursor::canDelete() const +{ + return ( ( d->md & Delete ) == Delete ) ; +} + +/*! + \overload + + Returns a formatted string composed of the \a prefix (e.g. table + or view name), ".", the \a field name, the \a fieldSep and the + field value. If the \a prefix is empty then the string will begin + with the \a field name. This function is useful for generating SQL + statements. +*/ + +QString QSqlCursor::toString( const QString& prefix, QSqlField* field, const QString& fieldSep ) const +{ + QString f; + if ( field && driver() ) { + f = ( prefix.length() > 0 ? prefix + QString(".") : QString::null ) + field->name(); + f += " " + fieldSep + " "; + if ( field->isNull() ) { + f += "NULL"; + } else { + f += driver()->formatValue( field ); + } + } + return f; +} + +/*! + Returns a formatted string composed of all the fields in \a rec. + Each field is composed of the \a prefix (e.g. table or view name), + ".", the field name, the \a fieldSep and the field value. If the + \a prefix is empty then each field will begin with the field name. + The fields are then joined together separated by \a sep. Fields + where isGenerated() returns FALSE are not included. This function + is useful for generating SQL statements. +*/ + +QString QSqlCursor::toString( QSqlRecord* rec, const QString& prefix, const QString& fieldSep, + const QString& sep ) const +{ + static QString blank( " " ); + QString filter; + bool separator = FALSE; + for ( uint j = 0; j < count(); ++j ) { + QSqlField* f = rec->field( j ); + if ( rec->isGenerated( j ) ) { + if ( separator ) + filter += sep + blank; + filter += toString( prefix, f, fieldSep ); + filter += blank; + separator = TRUE; + } + } + return filter; +} + +/*! + \overload + + Returns a formatted string composed of all the fields in the index + \a i. Each field is composed of the \a prefix (e.g. table or view + name), ".", the field name, the \a fieldSep and the field value. + If the \a prefix is empty then each field will begin with the field + name. The field values are taken from \a rec. The fields are then + joined together separated by \a sep. Fields where isGenerated() + returns FALSE are ignored. This function is useful for generating + SQL statements. +*/ + +QString QSqlCursor::toString( const QSqlIndex& i, QSqlRecord* rec, const QString& prefix, + const QString& fieldSep, const QString& sep ) const +{ + QString filter; + bool separator = FALSE; + for( uint j = 0; j < i.count(); ++j ){ + if ( rec->isGenerated( j ) ) { + if( separator ) { + filter += " " + sep + " " ; + } + QString fn = i.fieldName( j ); + QSqlField* f = rec->field( fn ); + filter += toString( prefix, f, fieldSep ); + separator = TRUE; + } + } + return filter; +} + +/*! + \overload + + Inserts the current contents of the cursor's edit record buffer + into the database, if the cursor allows inserts. Returns the + number of rows affected by the insert. For error information, use + lastError(). + + If \a invalidate is TRUE (the default), the cursor will no longer + be positioned on a valid record and can no longer be navigated. A + new select() call must be made before navigating to a valid + record. + + \quotefile sql/overview/insert2/main.cpp + \skipto prices + \printline prices + \printuntil insert + + In the above example, a cursor is created on the 'prices' table + and a pointer to the insert buffer is aquired using primeInsert(). + Each field's value is set to the desired value and then insert() + is called to insert the data into the database. Remember: all edit + operations (insert(), update() and delete()) operate on the + contents of the cursor edit buffer and not on the contents of the + cursor itself. + + \sa setMode() lastError() +*/ + +int QSqlCursor::insert( bool invalidate ) +{ + if ( ( d->md & Insert ) != Insert || !driver() ) + return FALSE; + int k = d->editBuffer.count(); + if ( k == 0 ) + return 0; + + QString fList; + QString vList; + bool comma = FALSE; + // use a prepared query if the driver supports it + if ( driver()->hasFeature( QSqlDriver::PreparedQueries ) ) { + int cnt = 0; + bool oraStyle = driver()->hasFeature( QSqlDriver::NamedPlaceholders ); + for( int j = 0; j < k; ++j ) { + QSqlField* f = d->editBuffer.field( j ); + if ( d->editBuffer.isGenerated( j ) ) { + if ( comma ) { + fList += ","; + vList += ","; + } + fList += f->name(); + vList += (oraStyle == TRUE) ? ":f" + QString::number(cnt) : QString("?"); + cnt++; + comma = TRUE; + } + } + if ( !comma ) { + return 0; + } + QString str; + str.append( "insert into " ).append( name() ).append( "(" ).append( fList ).append( ") values (" ).append( vList ). append ( ")" ); + return applyPrepared( str, invalidate ); + } else { + for( int j = 0; j < k; ++j ) { + QSqlField* f = d->editBuffer.field( j ); + if ( d->editBuffer.isGenerated( j ) ) { + if ( comma ) { + fList += ","; + vList += ","; + } + fList += f->name(); + vList += driver()->formatValue( f ); + comma = TRUE; + } + } + + if ( !comma ) { + // no valid fields found + return 0; + } + QString str; + str.append( "insert into " ).append( name() ).append( "(" ).append( fList ).append( ") values (" ).append( vList ). append ( ")" ); + return apply( str, invalidate ); + } +} + +/*! + Returns the current internal edit buffer. If \a copy is TRUE (the + default is FALSE), the current cursor field values are first + copied into the edit buffer. The edit buffer is valid as long as + the cursor remains valid. The cursor retains ownership of the + returned pointer, so it must not be deleted or modified. + + \sa primeInsert(), primeUpdate() primeDelete() +*/ + +QSqlRecord* QSqlCursor::editBuffer( bool copy ) +{ + if ( copy ) { + for(uint i = 0; i < d->editBuffer.count(); i++) { + if ( QSqlRecord::isNull( i ) ) { + d->editBuffer.setNull( i ); + } else { + d->editBuffer.setValue( i, value( i ) ); + } + } + } + return &d->editBuffer; +} + +/*! + This function primes the edit buffer's field values for update and + returns the edit buffer. The default implementation copies the + field values from the current cursor record into the edit buffer + (therefore, this function is equivalent to calling editBuffer( + TRUE ) ). The cursor retains ownership of the returned pointer, so + it must not be deleted or modified. + + \sa editBuffer() update() +*/ + +QSqlRecord* QSqlCursor::primeUpdate() +{ + // memorize the primary keys as they were before the user changed the values in editBuffer + QSqlRecord* buf = editBuffer( TRUE ); + QSqlIndex idx = primaryIndex( FALSE ); + if ( !idx.isEmpty() ) + d->editIndex = toString( idx, buf, d->nm, "=", "and" ); + else + d->editIndex = qWhereClause( buf, d->nm, "and", driver() ); + return buf; +} + +/*! + This function primes the edit buffer's field values for delete and + returns the edit buffer. The default implementation copies the + field values from the current cursor record into the edit buffer + (therefore, this function is equivalent to calling editBuffer( + TRUE ) ). The cursor retains ownership of the returned pointer, so + it must not be deleted or modified. + + \sa editBuffer() del() +*/ + +QSqlRecord* QSqlCursor::primeDelete() +{ + return editBuffer( TRUE ); +} + +/*! + This function primes the edit buffer's field values for insert and + returns the edit buffer. The default implementation clears all + field values in the edit buffer. The cursor retains ownership of + the returned pointer, so it must not be deleted or modified. + + \sa editBuffer() insert() +*/ + +QSqlRecord* QSqlCursor::primeInsert() +{ + d->editBuffer.clearValues(); + return &d->editBuffer; +} + + +/*! + Updates the database with the current contents of the edit buffer. + Returns the number of records which were updated. + For error information, use lastError(). + + Only records which meet the filter criteria specified by the + cursor's primary index are updated. If the cursor does not contain + a primary index, no update is performed and 0 is returned. + + If \a invalidate is TRUE (the default), the current cursor can no + longer be navigated. A new select() call must be made before you + can move to a valid record. For example: + + \quotefile sql/overview/update/main.cpp + \skipto prices + \printline prices + \printuntil update + \printline + + In the above example, a cursor is created on the 'prices' table + and is positioned on the record to be updated. Then a pointer to + the cursor's edit buffer is acquired using primeUpdate(). A new + value is calculated and placed into the edit buffer with the + setValue() call. Finally, an update() call is made on the cursor + which uses the tables's primary index to update the record in the + database with the contents of the cursor's edit buffer. Remember: + all edit operations (insert(), update() and delete()) operate on + the contents of the cursor edit buffer and not on the contents of + the cursor itself. + + Note that if the primary index does not uniquely distinguish + records the database may be changed into an inconsistent state. + + \sa setMode() lastError() +*/ + +int QSqlCursor::update( bool invalidate ) +{ + if ( d->editIndex.isEmpty() ) + return 0; + return update( d->editIndex, invalidate ); +} + +/*! + \overload + + Updates the database with the current contents of the cursor edit + buffer using the specified \a filter. Returns the number of + records which were updated. + For error information, use lastError(). + + Only records which meet the filter criteria are updated, otherwise + all records in the table are updated. + + If \a invalidate is TRUE (the default), the cursor can no longer + be navigated. A new select() call must be made before you can move + to a valid record. + + \sa primeUpdate() setMode() lastError() +*/ + +int QSqlCursor::update( const QString & filter, bool invalidate ) +{ + if ( ( d->md & Update ) != Update ) { + return FALSE; + } + int k = count(); + if ( k == 0 ) { + return 0; + } + + // use a prepared query if the driver supports it + if ( driver()->hasFeature( QSqlDriver::PreparedQueries ) ) { + QString fList; + bool comma = FALSE; + int cnt = 0; + bool oraStyle = driver()->hasFeature( QSqlDriver::NamedPlaceholders ); + for( int j = 0; j < k; ++j ) { + QSqlField* f = d->editBuffer.field( j ); + if ( d->editBuffer.isGenerated( j ) ) { + if ( comma ) { + fList += ","; + } + fList += f->name() + " = " + (oraStyle == TRUE ? ":f" + QString::number(cnt) : QString("?")); + cnt++; + comma = TRUE; + } + } + if ( !comma ) { + return 0; + } + QString str = "update " + name() + " set " + fList; + if ( filter.length() ) { + str+= " where " + filter; + } + return applyPrepared( str, invalidate ); + } else { + QString str = "update " + name(); + str += " set " + toString( &d->editBuffer, QString::null, "=", "," ); + if ( filter.length() ) { + str+= " where " + filter; + } + return apply( str, invalidate ); + } +} + +/*! + Deletes a record from the database using the cursor's primary + index and the contents of the cursor edit buffer. Returns the + number of records which were deleted. + For error information, use lastError(). + + Only records which meet the filter criteria specified by the + cursor's primary index are deleted. If the cursor does not contain + a primary index, no delete is performed and 0 is returned. If \a + invalidate is TRUE (the default), the current cursor can no longer + be navigated. A new select() call must be made before you can move + to a valid record. For example: + + \quotefile sql/overview/delete/main.cpp + \skipto prices + \printline prices + \printuntil } + + In the above example, a cursor is created on the 'prices' table + and positioned to the record to be deleted. First primeDelete() is + called to populate the edit buffer with the current cursor values, + e.g. with an id of 999, and then del() is called to actually + delete the record from the database. Remember: all edit operations + (insert(), update() and delete()) operate on the contents of the + cursor edit buffer and not on the contents of the cursor itself. + + \sa primeDelete() setMode() lastError() +*/ + +int QSqlCursor::del( bool invalidate ) +{ + QSqlIndex idx = primaryIndex( FALSE ); + if ( idx.isEmpty() ) + return del( qWhereClause( &d->editBuffer, d->nm, "and", driver() ), invalidate ); + else + return del( toString( primaryIndex(), &d->editBuffer, d->nm, + "=", "and" ), invalidate ); +} + +/*! + \overload + + Deletes the current cursor record from the database using the + filter \a filter. Only records which meet the filter criteria are + deleted. Returns the number of records which were deleted. If \a + invalidate is TRUE (the default), the current cursor can no longer + be navigated. A new select() call must be made before you can move + to a valid record. For error information, use lastError(). + + The \a filter is an SQL \c WHERE clause, e.g. \c{id=500}. + + \sa setMode() lastError() +*/ + +int QSqlCursor::del( const QString & filter, bool invalidate ) +{ + if ( ( d->md & Delete ) != Delete ) + return 0; + int k = count(); + if( k == 0 ) return 0; + QString str = "delete from " + name(); + if ( filter.length() ) + str+= " where " + filter; + return apply( str, invalidate ); +} + +/* + \internal +*/ + +int QSqlCursor::apply( const QString& q, bool invalidate ) +{ + int ar = 0; + if ( invalidate ) { + if ( exec( q ) ) + ar = numRowsAffected(); + } else if ( driver() ) { + QSqlQuery* sql = d->query(); + if ( sql && sql->exec( q ) ) + ar = sql->numRowsAffected(); + } + return ar; +} + +/* + \internal +*/ + +int QSqlCursor::applyPrepared( const QString& q, bool invalidate ) +{ + int ar = 0; + QSqlQuery* sql = 0; + + if ( invalidate ) { + sql = (QSqlQuery*)this; + d->lastAt = QSql::BeforeFirst; + } else { + sql = d->query(); + } + if ( !sql ) + return 0; + + if ( invalidate || sql->lastQuery() != q ) { + if ( !sql->prepare( q ) ) + return 0; + } + + int cnt = 0; + int fieldCount = (int)count(); + for ( int j = 0; j < fieldCount; ++j ) { + const QSqlField* f = d->editBuffer.field( j ); + if ( d->editBuffer.isGenerated( j ) ) { + sql->bindValue( cnt, f->value() ); + cnt++; + } + } + if ( sql->exec() ) { + ar = sql->numRowsAffected(); + } + return ar; +} + +/*! \reimp + + Executes the SQL query \a sql. Returns TRUE of the cursor is + active, otherwise returns FALSE. + +*/ +bool QSqlCursor::exec( const QString & sql ) +{ + d->lastAt = QSql::BeforeFirst; + QSqlQuery::exec( sql ); + return isActive(); +} + +/*! + Protected virtual function which is called whenever a field needs + to be calculated. If calculated fields are being used, derived + classes must reimplement this function and return the appropriate + value for field \a name. The default implementation returns an + invalid QVariant. + + \sa setCalculated() +*/ + +QVariant QSqlCursor::calculateField( const QString& ) +{ + return QVariant(); +} + +/*! \internal + Ensure fieldlist is synced with query. + +*/ + +static QString qTrim( const QString& s ) +{ + QString result = s; + int end = result.length() - 1; + while ( end >= 0 && result[end].isSpace() ) // skip white space from end + end--; + result.truncate( end + 1 ); + return result; +} + +/*! \internal + */ + +void QSqlCursor::sync() +{ + if ( isActive() && isValid() && d->lastAt != at() ) { + d->lastAt = at(); + uint i = 0; + uint j = 0; + bool haveCalculatedFields = FALSE; + for ( ; i < count(); ++i ) { + if ( !haveCalculatedFields && d->infoBuffer[i].isCalculated() ) { + haveCalculatedFields = TRUE; + } + if ( QSqlRecord::isGenerated( i ) ) { + QVariant v = QSqlQuery::value( j ); + if ( ( v.type() == QVariant::String || v.type() == QVariant::CString ) && + d->infoBuffer[ i ].isTrim() ) { + v = qTrim( v.toString() ); + } + QSqlRecord::setValue( i, v ); + if ( QSqlQuery::isNull( j ) ) + QSqlRecord::field( i )->setNull(); + j++; + } + } + if ( haveCalculatedFields ) { + for ( i = 0; i < count(); ++i ) { + if ( d->infoBuffer[i].isCalculated() ) + QSqlRecord::setValue( i, calculateField( fieldName( i ) ) ); + } + } + } +} + +/*! \reimp + +*/ + +void QSqlCursor::afterSeek() +{ + sync(); +} + +/*! + \reimp + + Returns the value of field number \a i. +*/ + +QVariant QSqlCursor::value( int i ) const +{ + return QSqlRecord::value( i ); +} + +/*! + \reimp + + Returns the value of the field called \a name. +*/ + +QVariant QSqlCursor::value( const QString& name ) const +{ + return QSqlRecord::value( name ); +} + +/*! \internal + cursors should be filled with QSqlFieldInfos... +*/ +void QSqlCursor::append( const QSqlField& field ) +{ + append( QSqlFieldInfo( field ) ); +} +/*! \internal + cursors should be filled with QSqlFieldInfos... +*/ +void QSqlCursor::insert( int pos, const QSqlField& field ) +{ + insert( pos, QSqlFieldInfo( field ) ); +} + +/*! + Returns TRUE if the field \a i is NULL or if there is no field at + position \a i; otherwise returns FALSE. + + This is the same as calling QSqlRecord::isNull( \a i ) +*/ +bool QSqlCursor::isNull( int i ) const +{ + return QSqlRecord::isNull( i ); +} +/*! + \overload + + Returns TRUE if the field called \a name is NULL or if there is no + field called \a name; otherwise returns FALSE. + + This is the same as calling QSqlRecord::isNull( \a name ) +*/ +bool QSqlCursor::isNull( const QString& name ) const +{ + return QSqlRecord::isNull( name ); +} + +/*! \reimp */ +void QSqlCursor::setValue( int i, const QVariant& val ) +{ +#ifdef QT_DEBUG + qDebug("QSqlCursor::setValue(): This will not affect actual database values. Use primeInsert(), primeUpdate() or primeDelete()."); +#endif + QSqlRecord::setValue( i, val ); +} + +/*! \reimp */ +void QSqlCursor::setValue( const QString& name, const QVariant& val ) +{ +#ifdef QT_DEBUG + qDebug("QSqlCursor::setValue(): This will not affect actual database values. Use primeInsert(), primeUpdate() or primeDelete()."); +#endif + QSqlRecord::setValue( name, val ); +} +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlcursor.h b/main/dependencies/qt3/src/sql/qsqlcursor.h new file mode 100644 index 000000000..22d15b078 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlcursor.h @@ -0,0 +1,160 @@ +/**************************************************************************** +** +** Definition of QSqlCursor class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLCURSOR_H +#define QSQLCURSOR_H + +#ifndef QT_H +#include "qsqlrecord.h" +#include "qstringlist.h" +#include "qsqlquery.h" +#include "qsqlindex.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL + +class QSqlDatabase; +class QSqlCursorPrivate; + +class QM_EXPORT_SQL QSqlCursor : public QSqlRecord, public QSqlQuery +{ +public: + QSqlCursor( const QString & name = QString::null, bool autopopulate = TRUE, QSqlDatabase* db = 0 ); + QSqlCursor( const QSqlCursor & other ); + QSqlCursor& operator=( const QSqlCursor& other ); + ~QSqlCursor(); + + enum Mode { + ReadOnly = 0, + Insert = 1, + Update = 2, + Delete = 4, + Writable = 7 + }; + + 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 ); + virtual QSqlIndex primaryIndex( bool prime = TRUE ) const; + virtual QSqlIndex index( const QStringList& fieldNames ) const; + QSqlIndex index( const QString& fieldName ) const; + QSqlIndex index( const char* fieldName ) const; + virtual void setPrimaryIndex( const QSqlIndex& idx ); + + virtual void append( const QSqlFieldInfo& fieldInfo ); + virtual void insert( int pos, const QSqlFieldInfo& fieldInfo ); + void remove( int pos ); + void clear(); + void setGenerated( const QString& name, bool generated ); + void setGenerated( int i, bool generated ); + + virtual QSqlRecord* editBuffer( bool copy = FALSE ); + virtual QSqlRecord* primeInsert(); + virtual QSqlRecord* primeUpdate(); + virtual QSqlRecord* primeDelete(); + virtual int insert( bool invalidate = TRUE ); + virtual int update( bool invalidate = TRUE ); + virtual int del( bool invalidate = TRUE ); + + virtual void setMode( int flags ); + int mode() const; + virtual void setCalculated( const QString& name, bool calculated ); + bool isCalculated( const QString& name ) const; + virtual void setTrimmed( const QString& name, bool trim ); + bool isTrimmed( const QString& name ) const; + + bool isReadOnly() const; + bool canInsert() const; + bool canUpdate() const; + bool canDelete() const; + + bool select(); + bool select( const QSqlIndex& sort ); + bool select( const QSqlIndex & filter, const QSqlIndex & sort ); + virtual bool select( const QString & filter, const QSqlIndex & sort = QSqlIndex() ); + + virtual void setSort( const QSqlIndex& sort ); + QSqlIndex sort() const; + virtual void setFilter( const QString& filter ); + QString filter() const; + virtual void setName( const QString& name, bool autopopulate = TRUE ); + QString name() const; + QString toString( const QString& prefix = QString::null, + const QString& sep = "," ) const; + bool isNull( int i ) const; + bool isNull( const QString& name ) const; + +protected: + void afterSeek(); + bool exec( const QString & sql ); + + virtual QVariant calculateField( const QString& name ); + virtual int update( const QString & filter, bool invalidate = TRUE ); + virtual int del( const QString & filter, bool invalidate = TRUE ); + + virtual QString toString( const QString& prefix, QSqlField* field, const QString& fieldSep ) const; + virtual QString toString( QSqlRecord* rec, const QString& prefix, const QString& fieldSep, + const QString& sep ) const; + virtual QString toString( const QSqlIndex& i, QSqlRecord* rec, const QString& prefix, + const QString& fieldSep, const QString& sep ) const; + +private: + void sync(); + int apply( const QString& q, bool invalidate ); + int applyPrepared( const QString& q, bool invalidate ); + QSqlRecord& operator=( const QSqlRecord & list ); + void append( const QSqlField& field ); + void insert( int pos, const QSqlField& field ); + + QSqlCursorPrivate* d; +}; + + + + +#endif // QT_NO_SQL +#endif diff --git a/main/dependencies/qt3/src/sql/qsqldatabase.cpp b/main/dependencies/qt3/src/sql/qsqldatabase.cpp new file mode 100644 index 000000000..eaa7a7064 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqldatabase.cpp @@ -0,0 +1,1332 @@ +/**************************************************************************** +** +** Implementation of QSqlDatabase class +** +** Created : 2000-11-03 +** +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqldatabase.h" + +#ifndef QT_NO_SQL + +#ifdef Q_OS_WIN32 +// Conflicting declarations of LPCBYTE in sqlfront.h and winscard.h +#define _WINSCARD_H_ +#endif + +#ifdef QT_SQL_POSTGRES +#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_IBASE +#include "drivers/ibase/qsql_ibase.h" +#endif + +#include "qapplication.h" +#include "qsqlresult.h" +#include "qsqldriver.h" +#include "qsqldriverinterface_p.h" +#include <private/qpluginmanager_p.h> +#include <private/qsqlextension_p.h> +#include "qobject.h" +#include "qguardedptr.h" +#include "qcleanuphandler.h" +#include "qdict.h" +#include <stdlib.h> + +QT_STATIC_CONST_IMPL char * const QSqlDatabase::defaultConnection = "qt_sql_default_connection"; + +QPtrDict<QSqlDriverExtension> *qt_driver_extension_dict = 0; +QPtrDict<QSqlOpenExtension> *qt_open_extension_dict = 0; + +static QSingleCleanupHandler< QPtrDict<QSqlDriverExtension> > qt_driver_ext_cleanup; +static QSingleCleanupHandler< QPtrDict<QSqlOpenExtension> > qt_open_ext_cleanup; + +Q_EXPORT QPtrDict<QSqlDriverExtension> *qSqlDriverExtDict() +{ + if ( !qt_driver_extension_dict ) { + qt_driver_extension_dict = new QPtrDict<QSqlDriverExtension>; + qt_driver_ext_cleanup.set( &qt_driver_extension_dict ); + } + return qt_driver_extension_dict; +} + +Q_EXPORT QPtrDict<QSqlOpenExtension> *qSqlOpenExtDict() +{ + if ( !qt_open_extension_dict ) { + qt_open_extension_dict = new QPtrDict<QSqlOpenExtension>; + qt_open_ext_cleanup.set( &qt_open_extension_dict ); + } + return qt_open_extension_dict; +} + +class QNullResult : public QSqlResult +{ +public: + QNullResult(const QSqlDriver* d): QSqlResult(d){} + ~QNullResult(){} +protected: + QVariant data( int ) { return QVariant(); } + bool reset ( const QString& sqlquery ) { QString s(sqlquery); return FALSE; } + bool fetch( int i ) { i = i; return FALSE; } + bool fetchFirst() { return FALSE; } + bool fetchLast() { return FALSE; } + bool isNull( int ) {return FALSE; } + QSqlRecord record() {return QSqlRecord();} + int size() {return 0;} + int numRowsAffected() {return 0;} +}; + +class QNullDriver : public QSqlDriver +{ +public: + QNullDriver(): QSqlDriver(){} + ~QNullDriver(){} + bool hasFeature( DriverFeature /* f */ ) const { return FALSE; } ; + bool open( const QString & , + const QString & , + const QString & , + const QString &, + int ) { + return FALSE; + } + void close() {} + QSqlQuery createQuery() const { return QSqlQuery( new QNullResult(this) ); } +}; + +typedef QDict<QSqlDriverCreatorBase> QDriverDict; + +class QSqlDatabaseManager : public QObject +{ +public: + QSqlDatabaseManager( QObject * parent = 0, const char * name = 0 ); + ~QSqlDatabaseManager(); + static QSqlDatabase* database( const QString& name, bool open ); + static QSqlDatabase* addDatabase( QSqlDatabase* db, const QString & name ); + static void removeDatabase( const QString& name ); + static void removeDatabase( QSqlDatabase* db ); + static bool contains( const QString& name ); + static QDriverDict* driverDict(); + +protected: + static QSqlDatabaseManager* instance(); + QDict< QSqlDatabase > dbDict; + QDriverDict* drDict; +}; + +/*! + Constructs an SQL database manager. +*/ + +QSqlDatabaseManager::QSqlDatabaseManager( QObject * parent, const char * name ) + : QObject( parent, name ), dbDict( 1 ), drDict( 0 ) +{ +} + +/*! + Destroys the object and frees any allocated resources. All open + database connections are closed. All database connections are + deleted. +*/ + +QSqlDatabaseManager::~QSqlDatabaseManager() +{ + QDictIterator< QSqlDatabase > it( dbDict ); + while ( it.current() ) { + it.current()->close(); + delete it.current(); + ++it; + } + delete drDict; +} + +/*! + \internal +*/ +QDriverDict* QSqlDatabaseManager::driverDict() +{ + QSqlDatabaseManager* sqlConnection = instance(); + if ( !sqlConnection->drDict ) { + sqlConnection->drDict = new QDriverDict(); + sqlConnection->drDict->setAutoDelete( TRUE ); + } + return sqlConnection->drDict; +} + + +/*! + \internal +*/ +QSqlDatabaseManager* QSqlDatabaseManager::instance() +{ + static QGuardedPtr<QSqlDatabaseManager> sqlConnection = 0; + if ( !sqlConnection ) { + if( qApp == 0 ){ + qFatal( "QSqlDatabaseManager: A QApplication object has to be " + "instantiated in order to use the SQL module." ); + return 0; + } + sqlConnection = new QSqlDatabaseManager( qApp, "database manager" ); + } + return (QSqlDatabaseManager*)sqlConnection; +} + +/*! + Returns the database connection called \a name. If \a open is + TRUE, the database connection is opened. If \a name does not exist + in the list of managed databases, 0 is returned. +*/ + +QSqlDatabase* QSqlDatabaseManager::database( const QString& name, bool open ) +{ + if ( !contains( name ) ) + return 0; + + QSqlDatabaseManager* sqlConnection = instance(); + QSqlDatabase* db = sqlConnection->dbDict.find( name ); + if ( db && !db->isOpen() && open ) { + db->open(); +#ifdef QT_CHECK_RANGE + if ( !db->isOpen() ) + qWarning("QSqlDatabaseManager::database: unable to open database: %s: %s", + db->lastError().databaseText().latin1(), db->lastError().driverText().latin1() ); +#endif + } + return db; +} + +/*! + Returns TRUE if the list of database connections contains \a name; + otherwise returns FALSE. +*/ + +bool QSqlDatabaseManager::contains( const QString& name ) +{ + QSqlDatabaseManager* sqlConnection = instance(); + QSqlDatabase* db = sqlConnection->dbDict.find( name ); + if ( db ) + return TRUE; + return FALSE; +} + + +/*! + Adds a database to the SQL connection manager. The database + connection is referred to by \a name. The newly added database + connection is returned. This function will only return 0 if it is + called \e before a QApplication object has been instantiated. Use + the output of drivers() to determine whether a particular driver + is available or not. + + The returned QSqlDatabase object is owned by the framework and + must not be deleted. If you want to explicitly remove the connection, + use removeDatabase(). + + \sa QSqlDatabase database() +*/ + +QSqlDatabase* QSqlDatabaseManager::addDatabase( QSqlDatabase* db, const QString & name ) +{ + QSqlDatabaseManager* sqlConnection = instance(); + if( sqlConnection == 0 ) + return 0; + if ( contains( name ) ) + sqlConnection->removeDatabase( name ); + sqlConnection->dbDict.insert( name, db ); + return db; +} + +/*! + Removes the database connection \a name from the SQL connection + manager. + + \warning There should be no open queries on the database + connection when this function is called, otherwise a resource leak + will occur. +*/ + +void QSqlDatabaseManager::removeDatabase( const QString& name ) +{ + QSqlDatabaseManager* sqlConnection = instance(); + sqlConnection->dbDict.setAutoDelete( TRUE ); + sqlConnection->dbDict.remove( name ); + sqlConnection->dbDict.setAutoDelete( FALSE ); +} + + +/*! + Removes the database connection \a db from the SQL connection + manager. The QSqlDatabase object is destroyed when it is removed + from the manager. + + \warning The \a db pointer is not valid after this function has + been called. +*/ + +void QSqlDatabaseManager::removeDatabase( QSqlDatabase* db ) +{ + QSqlDatabaseManager* sqlConnection = instance(); + if ( !sqlConnection ) + return; + QDictIterator< QSqlDatabase > it( sqlConnection->dbDict ); + while ( it.current() ) { + if ( it.current() == db ) { + sqlConnection->dbDict.remove( it.currentKey() ); + db->close(); + delete db; + break; + } + ++it; + } +} + +class QSqlDatabasePrivate +{ +public: + QSqlDatabasePrivate(): + driver(0), +#ifndef QT_NO_COMPONENT + plugIns(0), +#endif + port(-1) {} + ~QSqlDatabasePrivate() + { + } + QSqlDriver* driver; +#ifndef QT_NO_COMPONENT + QPluginManager<QSqlDriverFactoryInterface> *plugIns; +#endif + QString dbname; + QString uname; + QString pword; + QString hname; + QString drvName; + int port; + QString connOptions; +}; + +/*! + \class QSqlDatabase qsqldatabase.h + \brief The QSqlDatabase class is used to create SQL database + connections and to provide transaction handling. + + \ingroup database + \mainclass + \module sql + + Note that transaction handling is not supported by every SQL + database. You can find out whether transactions are supported + using QSqlDriver::hasFeature(). + + The QSqlDatabase class provides an abstract interface for + accessing many types of database backends. Database-specific + drivers are used internally to actually access and manipulate + data, (see QSqlDriver). Result set objects provide the interface + for executing and manipulating SQL queries (see QSqlQuery). +*/ + +/*! + Adds a database to the list of database connections using the + driver \a type and the connection name \a connectionName. + + The database connection is referred to by \a connectionName. The + newly added database connection is returned. This pointer is owned + by QSqlDatabase and will be deleted on program exit or when + removeDatabase() is called. + + 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 pointer to it. If \a + connectionName is given, use \link QSqlDatabase::database() + database(connectionName)\endlink 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. + + \sa database() removeDatabase() +*/ +QSqlDatabase* QSqlDatabase::addDatabase( const QString& type, const QString& connectionName ) +{ + return QSqlDatabaseManager::addDatabase( new QSqlDatabase( type, connectionName ), connectionName ); +} + +/*! + 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, 0 is + returned. The pointer returned is owned by QSqlDatabase and should + \e not be deleted. + + \warning There are restrictions on the use of database connections + in threaded applications. Please see the \link threads.html#threads-sql + Thread Support in Qt\endlink document for more information about + threading and SQL databases. +*/ + +QSqlDatabase* QSqlDatabase::database( const QString& connectionName, bool open ) +{ + return QSqlDatabaseManager::database( connectionName, open ); +} + +/*! + 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. +*/ + +void QSqlDatabase::removeDatabase( const QString& connectionName ) +{ + QSqlDatabaseManager::removeDatabase( connectionName ); +} + +/*! + \overload + + Removes the database connection \a db from the list of database + connections. The QSqlDatabase object is destroyed when it is removed + from the list. + + \warning The \a db pointer is not valid after this function has + been called. There should be no open queries on the database + connection when this function is called, otherwise a resource leak + will occur. +*/ + +void QSqlDatabase::removeDatabase( QSqlDatabase* db ) +{ + QSqlDatabaseManager::removeDatabase( db ); +} + +/*! + Returns a list of all the available database drivers. + + Note that if you want to iterate over the list, you should iterate + over a copy, e.g. + \code + QStringList list = QSqlDatabase::drivers(); + QStringList::Iterator it = list.begin(); + while( it != list.end() ) { + myProcessing( *it ); + ++it; + } + \endcode +*/ + +QStringList QSqlDatabase::drivers() +{ + QStringList l; + +#ifndef QT_NO_COMPONENT + QPluginManager<QSqlDriverFactoryInterface> *plugIns; + plugIns = new QPluginManager<QSqlDriverFactoryInterface>( IID_QSqlDriverFactory, QApplication::libraryPaths(), "/sqldrivers" ); + + l = plugIns->featureList(); + delete plugIns; +#endif + + QDictIterator<QSqlDriverCreatorBase> itd( *QSqlDatabaseManager::driverDict() ); + while ( itd.current() ) { + if ( !l.contains( itd.currentKey() ) ) + l << itd.currentKey(); + ++itd; + } + +#ifdef QT_SQL_POSTGRES + if ( !l.contains( "QPSQL7" ) ) + l << "QPSQL7"; +#endif +#ifdef QT_SQL_MYSQL + if ( !l.contains( "QMYSQL3" ) ) + l << "QMYSQL3"; +#endif +#ifdef QT_SQL_ODBC + if ( !l.contains( "QODBC3" ) ) + l << "QODBC3"; +#endif +#ifdef QT_SQL_OCI + if ( !l.contains( "QOCI8" ) ) + l << "QOCI8"; +#endif +#ifdef QT_SQL_TDS + if ( !l.contains( "QTDS7" ) ) + l << "QTDS7"; +#endif +#ifdef QT_SQL_DB2 + if ( !l.contains( "QDB2" ) ) + l << "QDB2"; +#endif +#ifdef QT_SQL_SQLITE + if ( !l.contains( "QSQLITE" ) ) + l << "QSQLITE"; +#endif +#ifdef QT_SQL_IBASE + if ( !l.contains( "QIBASE" ) ) + l << "QIBASE"; +#endif + + return l; +} + +/*! + 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 usage: + + \code + QSqlDatabase::registerSqlDriver( "MYDRIVER", new QSqlDriverCreator<MyDatabaseDriver> ); + QSqlDatabase* db = QSqlDatabase::addDatabase( "MYDRIVER" ); + ... + \endcode + + \warning The framework takes ownership of the \a creator pointer, + so it should not be deleted. +*/ +void QSqlDatabase::registerSqlDriver( const QString& name, const QSqlDriverCreatorBase* creator ) +{ + QSqlDatabaseManager::driverDict()->remove( name ); + if ( creator ) + QSqlDatabaseManager::driverDict()->insert( name, creator ); +} + +/*! + Returns TRUE if the list of database connections contains \a + connectionName; otherwise returns FALSE. +*/ + +bool QSqlDatabase::contains( const QString& connectionName ) +{ + return QSqlDatabaseManager::contains( connectionName ); +} + + +/*! + Creates a QSqlDatabase connection called \a name that uses the + driver referred to by \a type, with the parent \a parent and the + object name \a objname. If the \a type is not recognized, the + database connection will have no functionality. + + The currently available drivers are: + + \table + \header \i Driver Type \i Description + \row \i QODBC3 \i ODBC Driver (includes Microsoft SQL Server) + \row \i QOCI8 \i Oracle Call Interface Driver + \row \i QPSQL7 \i PostgreSQL v6.x and v7.x Driver + \row \i QTDS7 \i Sybase Adaptive Server + \row \i QMYSQL3 \i MySQL Driver + \row \i QDB2 \i IBM DB2, v7.1 and higher + \row \i QSQLITE \i SQLite Driver + \row \i QIBASE \i Borland Interbase Driver + \endtable + + Additional third party drivers, including your own custom drivers, + can be loaded dynamically. + + \sa registerSqlDriver() +*/ + +QSqlDatabase::QSqlDatabase( const QString& type, const QString& name, QObject * parent, const char * objname ) + : QObject( parent, objname ) +{ + init( type, name ); +} + + +/*! + \overload + + Creates a database connection using the driver \a driver, with + the parent \a parent and the object name \a objname. + + \warning The framework takes ownership of the \a driver pointer, + so it should not be deleted. +*/ + +QSqlDatabase::QSqlDatabase( QSqlDriver* driver, QObject * parent, const char * objname ) + : QObject( parent, objname ) +{ + d = new QSqlDatabasePrivate(); + d->driver = driver; +} + +/*! + \internal + + Create the actual driver instance \a type. +*/ + +void QSqlDatabase::init( const QString& type, const QString& ) +{ + d = new QSqlDatabasePrivate(); + d->drvName = type; + + if ( !d->driver ) { + +#ifdef QT_SQL_POSTGRES + if ( type == "QPSQL7" ) + d->driver = new QPSQLDriver(); +#endif + +#ifdef QT_SQL_MYSQL + if ( type == "QMYSQL3" ) + d->driver = new QMYSQLDriver(); +#endif + +#ifdef QT_SQL_ODBC + if ( type == "QODBC3" ) + d->driver = new QODBCDriver(); +#endif + +#ifdef QT_SQL_OCI + if ( type == "QOCI8" ) + d->driver = new QOCIDriver(); +#endif + +#ifdef QT_SQL_TDS + if ( type == "QTDS7" ) + d->driver = new QTDSDriver(); +#endif + +#ifdef QT_SQL_DB2 + if ( type == "QDB2" ) + d->driver = new QDB2Driver(); +#endif + +#ifdef QT_SQL_SQLITE + if ( type == "QSQLITE" ) + d->driver = new QSQLiteDriver(); +#endif + +#ifdef QT_SQL_IBASE + if ( type == "QIBASE" ) + d->driver = new QIBaseDriver(); +#endif + + } + + if ( !d->driver ) { + QDictIterator<QSqlDriverCreatorBase> it( *QSqlDatabaseManager::driverDict() ); + while ( it.current() && !d->driver ) { + if ( type == it.currentKey() ) { + d->driver = it.current()->createObject(); + } + ++it; + } + } + +#ifndef QT_NO_COMPONENT + if ( !d->driver ) { + d->plugIns = + new QPluginManager<QSqlDriverFactoryInterface>( IID_QSqlDriverFactory, QApplication::libraryPaths(), "/sqldrivers" ); + + QInterfacePtr<QSqlDriverFactoryInterface> iface = 0; + d->plugIns->queryInterface( type, &iface ); + if( iface ) + d->driver = iface->create( type ); + } +#endif + + if ( !d->driver ) { +#ifdef QT_CHECK_RANGE + qWarning( "QSqlDatabase: %s driver not loaded", type.latin1() ); + qWarning( "QSqlDatabase: available drivers: %s", drivers().join(" ").latin1() ); +#endif + d->driver = new QNullDriver(); + d->driver->setLastError( QSqlError( "Driver not loaded", "Driver not loaded" ) ); + } +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QSqlDatabase::~QSqlDatabase() +{ + delete d->driver; +#ifndef QT_NO_COMPONENT + delete d->plugIns; +#endif + delete d; +} + +/*! + Executes a SQL statement (e.g. an \c INSERT, \c UPDATE or \c + DELETE statement) on the database, and returns a QSqlQuery object. + Use lastError() to retrieve error information. If \a query is + QString::null, 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->createQuery(); + if ( !query.isNull() ) { + 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 the lastError() function. + + \sa lastError() +*/ + +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 a + connection and 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. + + \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 TRUE if the operation succeeded; otherwise + returns 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. Returns TRUE if the operation succeeded; otherwise + returns FALSE. + + \sa QSqlDriver::hasFeature() rollback() +*/ + +bool QSqlDatabase::commit() +{ + if ( !d->driver->hasFeature( QSqlDriver::Transactions ) ) + return FALSE; + return d->driver->commitTransaction(); +} + +/*! + Rolls a transaction back on the database if the driver supports + transactions. Returns TRUE if the operation succeeded; otherwise + returns FALSE. + + \sa QSqlDriver::hasFeature() commit() transaction() +*/ + +bool QSqlDatabase::rollback() +{ + if ( !d->driver->hasFeature( QSqlDriver::Transactions ) ) + return FALSE; + return d->driver->rollbackTransaction(); +} + +/*! + \property QSqlDatabase::databaseName + \brief the name of the database + + Note that the database name is the TNS Service Name for the QOCI8 + (Oracle) driver. + + For the QODBC3 driver it can either be a DSN, a DSN filename (the + file must have a \c .dsn extension), or a connection string. MS + Access users can for example use the following connection string + to open a \c .mdb file directly, instead of having to create a DSN + entry in the ODBC manager: + + \code + ... + db = QSqlDatabase::addDatabase( "QODBC3" ); + db->setDatabaseName( "DRIVER={Microsoft Access Driver (*.mdb)};FIL={MS Access};DBQ=myaccessfile.mdb" ); + if ( db->open() ) { + // success! + } + ... + \endcode + ("FIL" is the required spelling in Microsoft's API.) + + There is no default value. +*/ + +void QSqlDatabase::setDatabaseName( const QString& name ) +{ + d->dbname = name; +} + +/*! + \property QSqlDatabase::userName + \brief the user name connected to the database + + There is no default value. +*/ + +void QSqlDatabase::setUserName( const QString& name ) +{ + d->uname = name; +} + +/*! + \property QSqlDatabase::password + \brief the password used to connect to the database + + 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 behaviour. + + \sa open() +*/ + +void QSqlDatabase::setPassword( const QString& password ) +{ + d->pword = password; +} + +/*! + \property QSqlDatabase::hostName + \brief the host name where the database resides + + There is no default value. +*/ + +void QSqlDatabase::setHostName( const QString& host ) +{ + d->hname = host; +} + +/*! + \property QSqlDatabase::port + \brief the port used to connect to the database + + There is no default value. +*/ + +void QSqlDatabase::setPort( int p ) +{ + d->port = p; +} + +QString QSqlDatabase::databaseName() const +{ + return d->dbname; +} + +QString QSqlDatabase::userName() const +{ + return d->uname; +} + +QString QSqlDatabase::password() const +{ + return d->pword; +} + +QString QSqlDatabase::hostName() const +{ + return d->hname; +} + +/*! + Returns the name of the driver used by the database connection. +*/ +QString QSqlDatabase::driverName() const +{ + return d->drvName; +} + +int QSqlDatabase::port() const +{ + return d->port; +} + +/*! + Returns the database driver used to access the database + connection. +*/ + +QSqlDriver* QSqlDatabase::driver() const +{ + return d->driver; +} + +/*! + Returns information about the last error that occurred on the + database. See QSqlError for more information. +*/ + +QSqlError QSqlDatabase::lastError() const +{ + return d->driver->lastError(); +} + + +/*! + \overload + + Returns a list of the database's tables that are visible to the + user. To include views or system tables, use the version of this + function that takes a table \c type parameter. + + Note that if you want to iterate over the list, you should iterate + over a copy, e.g. + \code + QStringList list = myDatabase.tables(); + QStringList::Iterator it = list.begin(); + while( it != list.end() ) { + myProcessing( *it ); + ++it; + } + \endcode +*/ + +QStringList QSqlDatabase::tables() const +{ + return tables( QSql::Tables ); +} + +/*! + Returns a list of the database's tables, system tables and views, + as specified by the parameter \a type. + + Note that if you want to iterate over the list, you should iterate + over a copy, e.g. + \code + QStringList list = myDatabase.tables( QSql::Tables | QSql::Views ); + QStringList::Iterator it = list.begin(); + while( it != list.end() ) { + myProcessing( *it ); + ++it; + } + \endcode +*/ + +QStringList QSqlDatabase::tables( QSql::TableType type ) const +{ + return d->driver->tables( QString::number( (int)type ) ); +} + +/*! + Returns the primary index for table \a tablename. If no primary + index exists an empty QSqlIndex will be returned. +*/ + +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. + + \sa recordInfo() +*/ + +QSqlRecord QSqlDatabase::record( const QString& tablename ) const +{ + return d->driver->record( tablename ); +} + + +/*! + \overload + + Returns a QSqlRecord populated with the names of all the fields + used in the SQL \a query. If the query is a "SELECT *" the order + in which fields appear in the record is undefined. + + \sa recordInfo() +*/ + +QSqlRecord QSqlDatabase::record( const QSqlQuery& query ) const +{ + return d->driver->record( query ); +} + +/*! + Returns a QSqlRecordInfo populated with meta data about the table + or view \a tablename. If no such table (or view) exists, an empty + record is returned. + + \sa QSqlRecordInfo, QSqlFieldInfo, record() +*/ +QSqlRecordInfo QSqlDatabase::recordInfo( const QString& tablename ) const +{ + return d->driver->recordInfo( tablename ); +} + +/*! + \overload + + Returns a QSqlRecordInfo object with meta data for the QSqlQuery + \a query. Note that this overloaded function may return less + information than the recordInfo() function which takes the name of + a table as parameter. + + \sa QSqlRecordInfo, QSqlFieldInfo, record() +*/ +QSqlRecordInfo QSqlDatabase::recordInfo( const QSqlQuery& query ) const +{ + return d->driver->recordInfo( query ); +} + +/*! + \property QSqlDatabase::connectOptions + \brief the database connect options + + The format of the options string is a semi-colon 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 + \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 + \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 + \e none + + \i + \e none + + \endtable + + Example of usage: + \code + ... + // MySQL connection + db->setConnectOptions( "CLIENT_SSL;CLIENT_IGNORE_SPACE" ); // use an SSL connection to the server + if ( !db->open() ) { + db->setConnectOptions(); // clears the connect option string + ... + } + ... + // PostgreSQL connection + db->setConnectOptions( "requiressl=1" ); // enable PostgreSQL SSL connections + if ( !db->open() ) { + db->setConnectOptions(); // clear options + ... + } + ... + // ODBC connection + db->setConnectOptions( "SQL_ATTR_ACCESS_MODE=SQL_MODE_READ_ONLY;SQL_ATTR_TRACE=SQL_OPT_TRACE_ON" ); // set ODBC options + if ( !db->open() ) { + db->setConnectOptions(); // don't try to set this option + ... + } + \endcode + + Please refer to the client library documentation for more + information about the different options. The options will be set + prior to opening the database connection. Setting new options + without re-opening the connection does nothing. + + \sa connectOptions() +*/ + +void QSqlDatabase::setConnectOptions( const QString& options ) +{ + d->connOptions = options; +} + +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 ) +{ + QStringList l = drivers(); + QStringList::ConstIterator it = l.begin(); + for ( ;it != l.end(); ++it ) { + if ( *it == name ) + return TRUE; + } + return FALSE; +} + +/*! \overload + + This function is useful if you need to set up the database + connection and instantiate the driver yourself. If you do this, it + is recommended that you include the driver code in your own + application. For example, setting up a custom PostgreSQL + connection and instantiating the QPSQL7 driver can be done the + following way: + + \code + #include "qtdir/src/sql/drivers/psql/qsql_psql.cpp" + \endcode + (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. + + \code + PGconn* con = PQconnectdb( "host=server user=bart password=simpson dbname=springfield" ); + QPSQLDriver* drv = new QPSQLDriver( con ); + QSqlDatabase* db = QSqlDatabase::addDatabase( drv ); // becomes the new default connection + QSqlQuery q; + q.exec( "SELECT * FROM people" ); + ... + \endcode + + 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. + + Remember that you must link your application against the database + client library as well. The simplest way to do this is to add + lines like those below to your \c .pro file: + + \code + unix:LIBS += -lpq + win32:LIBS += libpqdll.lib + \endcode + + You will need to have the client library in your linker's search + path. + + The method described above will work for all the drivers, the only + difference is the arguments the driver constructors take. Below is + an overview of the drivers and their constructor arguments. + + \table + \header \i Driver \i Class name \i Constructor arguments \i File to include + \row + \i QPSQL7 + \i QPSQLDriver + \i PGconn* connection + \i \c qsql_psql.cpp + \row + \i QMYSQL3 + \i QMYSQLDriver + \i MYSQL* connection + \i \c qsql_mysql.cpp + \row + \i QOCI8 + \i QOCIDriver + \i OCIEnv* environment, OCIError* error, OCISvcCtx* serviceContext + \i \c qsql_oci.cpp + \row + \i QODBC3 + \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 QTDS7 + \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 + + Note: The host name (or service name) is needed when constructing + the QTDSDriver for creating new connections for internal + queries. This is to prevent the simultaneous usage of several + QSqlQuery/\l{QSqlCursor} objects from blocking each other. + + \warning The SQL framework takes ownership of the \a driver pointer, + and it should not be deleted. The returned QSqlDatabase object is + owned by the framework and must not be deleted. If you want to + explicitly remove the connection, use removeDatabase() + + \sa drivers() +*/ + +QSqlDatabase* QSqlDatabase::addDatabase( QSqlDriver* driver, const QString& connectionName ) +{ + return QSqlDatabaseManager::addDatabase( new QSqlDatabase( driver ), connectionName ); +} +#endif // QT_NO_SQL diff --git a/main/dependencies/qt3/src/sql/qsqldatabase.h b/main/dependencies/qt3/src/sql/qsqldatabase.h new file mode 100644 index 000000000..318695621 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqldatabase.h @@ -0,0 +1,155 @@ +/**************************************************************************** +** +** Definition of QSqlDatabase class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLDATABASE_H +#define QSQLDATABASE_H + +#ifndef QT_H +#include "qobject.h" +#include "qstring.h" +#include "qsqlquery.h" +#include "qstringlist.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL + +class QSqlError; +class QSqlDriver; +class QSqlIndex; +class QSqlRecord; +class QSqlRecordInfo; +class QSqlDatabasePrivate; + +class QM_EXPORT_SQL QSqlDriverCreatorBase +{ +public: + virtual QSqlDriver* createObject() = 0; +}; + +template <class type> +class QM_EXPORT_SQL QSqlDriverCreator: public QSqlDriverCreatorBase +{ +public: + QSqlDriver* createObject() { return new type; } +}; + +class QM_EXPORT_SQL QSqlDatabase : public QObject +{ + Q_OBJECT + Q_PROPERTY( QString databaseName READ databaseName WRITE setDatabaseName ) + Q_PROPERTY( QString userName READ userName WRITE setUserName ) + Q_PROPERTY( QString password READ password WRITE setPassword ) + Q_PROPERTY( QString hostName READ hostName WRITE setHostName ) + Q_PROPERTY( int port READ port WRITE setPort ) + Q_PROPERTY( QString connectOptions READ connectOptions WRITE setConnectOptions ) + +public: + ~QSqlDatabase(); + + bool open(); + bool open( const QString& user, const QString& password ); + void close(); + bool isOpen() const; + bool isOpenError() const; + QStringList tables() const; + QStringList tables( QSql::TableType type ) const; + QSqlIndex primaryIndex( const QString& tablename ) const; + QSqlRecord record( const QString& tablename ) const; + QSqlRecord record( const QSqlQuery& query ) const; + QSqlRecordInfo recordInfo( const QString& tablename ) const; + QSqlRecordInfo recordInfo( const QSqlQuery& query ) const; + QSqlQuery exec( const QString& query = QString::null ) const; + QSqlError lastError() const; + + bool transaction(); + bool commit(); + bool rollback(); + + virtual void setDatabaseName( const QString& name ); + virtual void setUserName( const QString& name ); + virtual void setPassword( const QString& password ); + virtual void setHostName( const QString& host ); + virtual void setPort( int p ); + void setConnectOptions( const QString& options = QString::null ); + QString databaseName() const; + QString userName() const; + QString password() const; + QString hostName() const; + QString driverName() const; + int port() const; + QString connectOptions() const; + + QSqlDriver* driver() const; + + // MOC_SKIP_BEGIN + QT_STATIC_CONST char * const defaultConnection; + // MOC_SKIP_END + + static QSqlDatabase* addDatabase( const QString& type, const QString& connectionName = defaultConnection ); + static QSqlDatabase* addDatabase( QSqlDriver* driver, const QString& connectionName = defaultConnection ); + static QSqlDatabase* database( const QString& connectionName = defaultConnection, bool open = TRUE ); + static void removeDatabase( const QString& connectionName ); + static void removeDatabase( QSqlDatabase* db ); + static bool contains( const QString& connectionName = defaultConnection ); + static QStringList drivers(); + static void registerSqlDriver( const QString& name, const QSqlDriverCreatorBase* creator ); // ### 4.0: creator should not be const + static bool isDriverAvailable( const QString& name ); + +protected: + QSqlDatabase( const QString& type, const QString& name, QObject * parent=0, const char * objname=0 ); + QSqlDatabase( QSqlDriver* driver, QObject * parent=0, const char * objname=0 ); +private: + void init( const QString& type, const QString& name ); + QSqlDatabasePrivate* d; +#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator= + QSqlDatabase( const QSqlDatabase & ); + QSqlDatabase &operator=( const QSqlDatabase & ); +#endif + +}; + +#endif // QT_NO_SQL +#endif diff --git a/main/dependencies/qt3/src/sql/qsqldriver.cpp b/main/dependencies/qt3/src/sql/qsqldriver.cpp new file mode 100644 index 000000000..78db42c49 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqldriver.cpp @@ -0,0 +1,509 @@ +/**************************************************************************** +** +** Implementation of QSqlDriver class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqldriver.h" + +#ifndef QT_NO_SQL + +#include "qdatetime.h" +#include "qsqlextension_p.h" + +// database states +#define DBState_Open 0x0001 +#define DBState_OpenError 0x0002 + +// ### This needs to go in 4.0! +QPtrDict<QSqlDriverExtension> *qSqlDriverExtDict(); +QPtrDict<QSqlOpenExtension> *qSqlOpenExtDict(); + +/*! + \class QSqlDriver qsqldriver.h + \brief The QSqlDriver class is an abstract base class for accessing + SQL databases. + + \ingroup database + \module sql + + This class should not be used directly. Use QSqlDatabase instead. +*/ + +/*! + Default constructor. Creates a new driver with parent \a parent, + called \a name. + +*/ + +QSqlDriver::QSqlDriver( QObject * parent, const char * name ) +: QObject(parent, name), + dbState(0), + error() +{ +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QSqlDriver::~QSqlDriver() +{ +} + +/*! + \fn bool QSqlDriver::open( const QString& db, const QString& user, + const QString& password, const QString& host, int port ) + + Derived classes must reimplement this abstract virtual function in + order to open a database connection on database \a db, using user + name \a user, password \a password, host \a host and port \a port. + + The function \e must return TRUE on success and FALSE on failure. + + \sa setOpen() + +*/ + +/*! + \fn bool QSqlDriver::close() + + Derived classes must reimplement this abstract virtual function in + order to close the database connection. Return TRUE on success, + FALSE on failure. + + \sa setOpen() + +*/ + +/*! + \fn QSqlQuery QSqlDriver::createQuery() const + + Creates an empty SQL result on the database. Derived classes must + reimplement this function and return a QSqlQuery object + appropriate for their database to the caller. + +*/ + +//void QSqlDriver::destroyResult( QSqlResult* r ) const +//{ +// if ( r ) +// delete r; +//} + +/*! + Returns TRUE if the database connection is open; otherwise returns + FALSE. +*/ + +bool QSqlDriver::isOpen() const +{ + if ( !qSqlDriverExtDict()->isEmpty() ) { + QSqlDriverExtension *ext = qSqlDriverExtDict()->find( (QSqlDriver *) this ); + if ( ext ) + return ext->isOpen(); + } + + return ((dbState & DBState_Open) == DBState_Open); +} + +/*! + Returns TRUE if the there was an error opening the database + connection; otherwise returns FALSE. +*/ + +bool QSqlDriver::isOpenError() const +{ + return ((dbState & DBState_OpenError) == DBState_OpenError); +} + +/*! + \enum QSqlDriver::DriverFeature + + This enum contains a list of features a driver may 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 usage of named placeholders + \value PositionalPlaceholders whether the driver supports usage of positional placeholders + + More information about supported features can be found in the + \link sql-driver.html Qt SQL driver\endlink documentation. + + \sa hasFeature() +*/ + +/*! + \fn bool QSqlDriver::hasFeature( DriverFeature f ) const + + Returns TRUE if the driver supports feature \a f; otherwise + returns FALSE. + + Note that some databases need to be open() before this can be + determined. + + \sa DriverFeature +*/ + +/*! + Protected function which sets the open state of the database to \a + o. Derived classes can use this function to report the status of + open(). + + \sa open(), setOpenError() +*/ + +void QSqlDriver::setOpen( bool o ) +{ + if ( o ) + dbState |= DBState_Open; + else + dbState &= ~DBState_Open; +} + +/*! + Protected function which sets the open error state of the database + to \a e. Derived classes can use this function to report the + status of open(). Note that if \a e is TRUE the open state of the + database is set to closed (i.e. isOpen() returns FALSE). + + \sa open(), setOpenError() +*/ + +void QSqlDriver::setOpenError( bool e ) +{ + if ( e ) { + dbState |= DBState_OpenError; + dbState &= ~DBState_Open; + } + else + dbState &= ~DBState_OpenError; +} + +/*! + Protected function which derived classes can reimplement to begin + a transaction. If successful, return TRUE, otherwise return FALSE. + The default implementation returns FALSE. + + \sa commitTransaction(), rollbackTransaction() +*/ + +bool QSqlDriver::beginTransaction() +{ + return FALSE; +} + +/*! + Protected function which derived classes can reimplement to commit + a transaction. If successful, return TRUE, otherwise return FALSE. + The default implementation returns FALSE. + + \sa beginTransaction(), rollbackTransaction() +*/ + +bool QSqlDriver::commitTransaction() +{ + return FALSE; +} + +/*! + Protected function which derived classes can reimplement to + rollback a transaction. If successful, return TRUE, otherwise + return FALSE. The default implementation returns FALSE. + + \sa beginTransaction(), commitTransaction() +*/ + +bool QSqlDriver::rollbackTransaction() +{ + return FALSE; +} + +/*! + Protected function which allows derived classes to set the value + of the last error, \a e, that occurred on the database. + + \sa lastError() +*/ + +void QSqlDriver::setLastError( const QSqlError& e ) +{ + error = e; +} + +/*! + Returns a QSqlError object which contains information about the + last error that occurred on the database. +*/ + +QSqlError QSqlDriver::lastError() const +{ + return error; +} + +/*! + Returns a list of 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 + downward compatibility. + + \sa QSql::TableType +*/ + +QStringList QSqlDriver::tables( const QString& ) 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& ) const +{ + return QSqlRecord(); +} + +/*! + \overload + + Returns a QSqlRecord populated with the names of the fields in the + SQL \a query. The default implementation returns an empty record. +*/ + +QSqlRecord QSqlDriver::record( const QSqlQuery& ) const +{ + return QSqlRecord(); +} + +/*! + Returns a QSqlRecordInfo object with meta data about the table \a + tablename. +*/ +QSqlRecordInfo QSqlDriver::recordInfo( const QString& tablename ) const +{ + return QSqlRecordInfo( record( tablename ) ); +} + +/*! + \overload + + Returns a QSqlRecordInfo object with meta data for the QSqlQuery + \a query. Note that this overloaded function may return less + information than the recordInfo() function which takes the name of + a table as parameter. +*/ +QSqlRecordInfo QSqlDriver::recordInfo( const QSqlQuery& query ) const +{ + return QSqlRecordInfo( record( query ) ); +} + + +/*! + Returns a string representation of the NULL value for the + database. This is used, for example, when constructing INSERT and + UPDATE statements. The default implementation returns the string + "NULL". +*/ + +QString QSqlDriver::nullText() const +{ + return "NULL"; +} + +/*! + 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 NULL, nullText() is returned. + + \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, nullText() is returned. + + \i If \a field is bytearray data, and the driver can edit binary + fields, the value is formatted as a hexadecimal string. + + \i For any other field type toString() will be called on its value + and the result returned. + + \endlist + + \sa QVariant::toString(). + +*/ +QString QSqlDriver::formatValue( const QSqlField* field, bool trimStrings ) const +{ + QString r; + if ( field->isNull() ) + r = nullText(); + else { + switch ( field->type() ) { + case QVariant::Int: + case QVariant::UInt: + if ( field->value().type() == QVariant::Bool ) + r = field->value().toBool() ? "1" : "0"; + else + r = field->value().toString(); + break; + case QVariant::Date: + if ( field->value().toDate().isValid() ) + r = "'" + field->value().toDate().toString( Qt::ISODate ) + "'"; + else + r = nullText(); + break; + case QVariant::Time: + if ( field->value().toTime().isValid() ) + r = "'" + field->value().toTime().toString( Qt::ISODate ) + "'"; + else + r = nullText(); + break; + case QVariant::DateTime: + if ( field->value().toDateTime().isValid() ) + r = "'" + + field->value().toDateTime().toString( Qt::ISODate ) + "'"; + else + r = nullText(); + break; + case QVariant::String: + case QVariant::CString: { + QString result = field->value().toString(); + if ( trimStrings ) { + int end = result.length() - 1; + while ( end && result[end].isSpace() ) /* skip white space from end */ + end--; + result.truncate( end ); + } + /* escape the "'" character */ + result.replace( QChar( '\'' ), "''" ); + r = "'" + result + "'"; + break; + } + case QVariant::Bool: + if ( field->value().toBool() ) + r = "1"; + else + r = "0"; + break; + case QVariant::ByteArray : { + if ( hasFeature( BLOB ) ) { + QByteArray ba = field->value().toByteArray(); + QString res; + static const char hexchars[] = "0123456789abcdef"; + for ( uint i = 0; i < ba.size(); ++i ) { + uchar s = (uchar) ba[(int)i]; + res += hexchars[s >> 4]; + res += hexchars[s & 0x0f]; + } + r = "'" + res + "'"; + break; + } + } + default: + r = field->value().toString(); + break; + } + } + return r; +} + +/*! + \overload + + 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 connOpts. + + Returns TRUE on success and FALSE on failure. + + \sa setOpen() +*/ +bool QSqlDriver::open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ) +{ + if ( !qSqlOpenExtDict()->isEmpty() ) { + QSqlOpenExtension *ext = qSqlOpenExtDict()->find( (QSqlDriver *) this ); + if ( ext ) + return ext->open( db, user, password, host, port, connOpts ); + } + return open( db, user, password, host, port ); +} + +#endif // QT_NO_SQL diff --git a/main/dependencies/qt3/src/sql/qsqldriver.h b/main/dependencies/qt3/src/sql/qsqldriver.h new file mode 100644 index 000000000..4115bc6f1 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqldriver.h @@ -0,0 +1,125 @@ +/**************************************************************************** +** +** Definition of QSqlDriver class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLDRIVER_H +#define QSQLDRIVER_H + +#ifndef QT_H +#include "qobject.h" +#include "qptrdict.h" +#include "qstring.h" +#include "qsqlerror.h" +#include "qsqlquery.h" +#include "qsqlfield.h" +#include "qsqlindex.h" +#include "qstringlist.h" +#include "qmap.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL + +class QSqlDriverExtension; + +class QSqlDatabase; + +class QM_EXPORT_SQL QSqlDriver : public QObject +{ + friend class QSqlDatabase; + Q_OBJECT +public: + enum DriverFeature { Transactions, QuerySize, BLOB, Unicode, PreparedQueries, + NamedPlaceholders, PositionalPlaceholders }; + + QSqlDriver( QObject * parent=0, const char * name=0 ); + ~QSqlDriver(); + bool isOpen() const; + bool isOpenError() const; + + virtual bool beginTransaction(); + virtual bool commitTransaction(); + virtual bool rollbackTransaction(); + virtual QStringList tables( const QString& tableType ) const; + virtual QSqlIndex primaryIndex( const QString& tableName ) const; + virtual QSqlRecord record( const QString& tableName ) const; + virtual QSqlRecord record( const QSqlQuery& query ) const; + virtual QSqlRecordInfo recordInfo( const QString& tablename ) const; + virtual QSqlRecordInfo recordInfo( const QSqlQuery& query ) const; + virtual QString nullText() const; + virtual QString formatValue( const QSqlField* field, bool trimStrings = FALSE ) const; + QSqlError lastError() const; + + virtual bool hasFeature( DriverFeature f ) const = 0; + virtual bool open( const QString & db, + const QString & user = QString::null, + const QString & password = QString::null, + const QString & host = QString::null, + int port = -1 ) = 0; + virtual void close() = 0; + virtual QSqlQuery createQuery() const = 0; + + // ### remove for 4.0 + bool open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ); +protected: + virtual void setOpen( bool o ); + virtual void setOpenError( bool e ); + virtual void setLastError( const QSqlError& e ); +private: + // ### This class needs a d-pointer in 4.0. + int dbState; + QSqlError error; +#if defined(Q_DISABLE_COPY) + QSqlDriver( const QSqlDriver & ); + QSqlDriver &operator=( const QSqlDriver & ); +#endif +}; + +#endif // QT_NO_SQL +#endif diff --git a/main/dependencies/qt3/src/sql/qsqldriverinterface_p.h b/main/dependencies/qt3/src/sql/qsqldriverinterface_p.h new file mode 100644 index 000000000..94df19a41 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqldriverinterface_p.h @@ -0,0 +1,85 @@ +/**************************************************************************** +** +** Definition of QSqlDriverInterface class +** +** Created : 2000-11-03 +** +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLDRIVERINTERFACE_H +#define QSQLDRIVERINTERFACE_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. +// +// + +#ifndef QT_H +#include <private/qcom_p.h> +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL + +#ifndef QT_NO_COMPONENT + +// {EDDD5AD5-DF3C-400c-A711-163B72FE5F61} +#ifndef IID_QSqlDriverFactory +#define IID_QSqlDriverFactory QUuid(0xeddd5ad5, 0xdf3c, 0x400c, 0xa7, 0x11, 0x16, 0x3b, 0x72, 0xfe, 0x5f, 0x61) +#endif + +class QSqlDriver; + +struct QM_EXPORT_SQL QSqlDriverFactoryInterface : public QFeatureListInterface +{ + virtual QSqlDriver* create( const QString& name ) = 0; +}; + +#endif //QT_NO_COMPONENT +#endif // QT_NO_SQL + +#endif // QSQLDRIVERINTERFACE_P_H diff --git a/main/dependencies/qt3/src/sql/qsqldriverplugin.cpp b/main/dependencies/qt3/src/sql/qsqldriverplugin.cpp new file mode 100644 index 000000000..224c616d1 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqldriverplugin.cpp @@ -0,0 +1,161 @@ +/**************************************************************************** +** +** Implementation of QSqlDriverPlugin class +** +** Created : 2001-09-20 +** +** Copyright (C) 2001-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqldriverplugin.h" + +#ifndef QT_NO_SQL +#ifndef QT_NO_COMPONENT + +#include "qsqldriverinterface_p.h" + +/*! + \class QSqlDriverPlugin qsqldriverplugin.h + \brief The QSqlDriverPlugin class provides an abstract base for custom QSqlDriver plugins. + + \ingroup plugins + \mainclass + + 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 \c Q_EXPORT_PLUGIN macro. See the SQL + plugins that come with Qt for example implementations (in the + \c{plugins/src/sqldrivers} subdirectory of the source + distribution). Read the \link plugins-howto.html plugins + documentation\endlink for more information on 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 key \a key. + The driver key is usually the class name of the required driver. + + \sa keys() +*/ + +class QSqlDriverPluginPrivate : public QSqlDriverFactoryInterface +{ +public: + QSqlDriverPluginPrivate( QSqlDriverPlugin *p ) + : plugin( p ) + { + } + virtual ~QSqlDriverPluginPrivate(); + + QRESULT queryInterface( const QUuid &iid, QUnknownInterface **iface ); + Q_REFCOUNT; + + QStringList featureList() const; + QSqlDriver *create( const QString &key ); + +private: + QSqlDriverPlugin *plugin; +}; + +QSqlDriverPluginPrivate::~QSqlDriverPluginPrivate() +{ + delete plugin; +} + +QRESULT QSqlDriverPluginPrivate::queryInterface( const QUuid &iid, QUnknownInterface **iface ) +{ + *iface = 0; + + if ( iid == IID_QUnknown ) + *iface = this; + else if ( iid == IID_QFeatureList ) + *iface = this; + else if ( iid == IID_QSqlDriverFactory ) + *iface = this; + else + return QE_NOINTERFACE; + + (*iface)->addRef(); + return QS_OK; +} + +QStringList QSqlDriverPluginPrivate::featureList() const +{ + return plugin->keys(); +} + +QSqlDriver *QSqlDriverPluginPrivate::create( const QString &key ) +{ + return plugin->create( key ); +} + +/*! + Constructs a SQL driver plugin. This is invoked automatically by + the \c Q_EXPORT_PLUGIN macro. +*/ + +QSqlDriverPlugin::QSqlDriverPlugin() + : QGPlugin( d = new QSqlDriverPluginPrivate( this ) ) +{ +} + +/*! + 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() +{ + // don't delete d, as this is deleted by d +} + +#endif // QT_NO_COMPONENT +#endif // QT_NO_SQL diff --git a/main/dependencies/qt3/src/sql/qsqldriverplugin.h b/main/dependencies/qt3/src/sql/qsqldriverplugin.h new file mode 100644 index 000000000..8949fd9f8 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqldriverplugin.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Definition of QSqlDriverPlugin class +** +** Created : 2001-09-20 +** +** Copyright (C) 2001-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLDRIVERPLUGIN_H +#define QSQLDRIVERPLUGIN_H + +#ifndef QT_H +#include "qgplugin.h" +#include "qstringlist.h" +#endif // QT_H + +#ifndef QT_NO_SQL +#ifndef QT_NO_COMPONENT + +class QSqlDriver; +class QSqlDriverPluginPrivate; + +class Q_EXPORT QSqlDriverPlugin : public QGPlugin +{ + Q_OBJECT +public: + QSqlDriverPlugin(); + ~QSqlDriverPlugin(); + + virtual QStringList keys() const = 0; + virtual QSqlDriver *create( const QString &key ) = 0; + +private: + QSqlDriverPluginPrivate *d; +}; + +#endif // QT_NO_COMPONENT +#endif // QT_NO_SQL + +#endif // QSQLDRIVERPLUGIN_H diff --git a/main/dependencies/qt3/src/sql/qsqleditorfactory.cpp b/main/dependencies/qt3/src/sql/qsqleditorfactory.cpp new file mode 100644 index 000000000..d0ce4e71f --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqleditorfactory.cpp @@ -0,0 +1,221 @@ +/**************************************************************************** +** +** Implementation of QSqlEditorFactory class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqleditorfactory.h" + +#ifndef QT_NO_SQL_EDIT_WIDGETS + +#include "qsqlfield.h" +#include "qcleanuphandler.h" +#include "qlabel.h" +#include "qlineedit.h" +#include "qspinbox.h" +#include "qcombobox.h" +#include "qdatetimeedit.h" + +/*! + \class QSqlEditorFactory qsqleditorfactory.h + \brief The QSqlEditorFactory class is used to create the editors + used by QDataTable and QSqlForm. + + \ingroup database + \module sql + + QSqlEditorFactory is used by QDataTable and QSqlForm to + automatically create appropriate editors for a given QSqlField. + For example if the field is a QVariant::String a QLineEdit would + be the default editor, whereas a QVariant::Int's default editor + would be a QSpinBox. + + If you want to create different editors for fields with the same + data type, subclass QSqlEditorFactory and reimplement the + createEditor() function. + + \sa QDataTable, QSqlForm +*/ + + +/*! + Constructs a SQL editor factory with parent \a parent, called \a + name. +*/ + +QSqlEditorFactory::QSqlEditorFactory ( QObject * parent, const char * name ) + : QEditorFactory( parent, name ) +{ + +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QSqlEditorFactory::~QSqlEditorFactory() +{ + +} + +static QSqlEditorFactory * defaultfactory = 0; +static QCleanupHandler< QSqlEditorFactory > qsql_cleanup_editor_factory; + +/*! + Returns an instance of a default editor factory. +*/ + +QSqlEditorFactory * QSqlEditorFactory::defaultFactory() +{ + if( defaultfactory == 0 ){ + defaultfactory = new QSqlEditorFactory(); + qsql_cleanup_editor_factory.add( &defaultfactory ); + } + + return defaultfactory; +} + +/*! + Replaces the default editor factory with \a factory. All + QDataTable and QSqlForm instantiations will use this new factory + for creating field editors. \e{QSqlEditorFactory takes ownership + of \a factory, and destroys it when it is no longer needed.} +*/ + +void QSqlEditorFactory::installDefaultFactory( QSqlEditorFactory * factory ) +{ + if( factory == 0 ) return; + + if( defaultfactory != 0 ){ + qsql_cleanup_editor_factory.remove( &defaultfactory ); + delete defaultfactory; + } + defaultfactory = factory; + qsql_cleanup_editor_factory.add( &defaultfactory ); +} + +/*! + Creates and returns the appropriate editor widget for the QVariant + \a variant. + + The widget that is returned has the parent \a parent (which may be + zero). If \a variant is invalid, 0 is returned. +*/ + +QWidget * QSqlEditorFactory::createEditor( QWidget * parent, + const QVariant & variant ) +{ + return QEditorFactory::createEditor( parent, variant ); +} + +/*! + \overload + + Creates and returns the appropriate editor for the QSqlField \a + field. +*/ + +QWidget * QSqlEditorFactory::createEditor( QWidget * parent, + const QSqlField * field ) +{ + if ( !field ) { + return 0; + } + + QWidget * w = 0; + switch( field->type() ){ + case QVariant::Invalid: + w = 0; + break; + case QVariant::Bool: + w = new QComboBox( parent, "qt_editor_bool" ); + ((QComboBox *) w)->insertItem( "False" ); + ((QComboBox *) w)->insertItem( "True" ); + break; + case QVariant::UInt: + w = new QSpinBox( 0, 2147483647, 1, parent, "qt_editor_spinbox" ); + break; + case QVariant::Int: + w = new QSpinBox( -2147483647, 2147483647, 1, parent, "qt_editor_int" ); + break; + case QVariant::LongLong: + case QVariant::ULongLong: + case QVariant::String: + case QVariant::CString: + case QVariant::Double: + w = new QLineEdit( parent, "qt_editor_double" ); + ((QLineEdit*)w)->setFrame( FALSE ); + break; + case QVariant::Date: + w = new QDateEdit( parent, "qt_editor_date" ); + break; + case QVariant::Time: + w = new QTimeEdit( parent, "qt_editor_time" ); + break; + case QVariant::DateTime: + w = new QDateTimeEdit( parent, "qt_editor_datetime" ); + break; +#ifndef QT_NO_LABEL + case QVariant::Pixmap: + w = new QLabel( parent, "qt_editor_pixmap" ); + break; +#endif + case QVariant::Palette: + case QVariant::ColorGroup: + case QVariant::Color: + case QVariant::Font: + case QVariant::Brush: + case QVariant::Bitmap: + case QVariant::Cursor: + case QVariant::Map: + case QVariant::StringList: + case QVariant::Rect: + case QVariant::Size: + case QVariant::IconSet: + case QVariant::Point: + case QVariant::PointArray: + case QVariant::Region: + case QVariant::SizePolicy: + case QVariant::ByteArray: + default: + w = new QWidget( parent, "qt_editor_default" ); + break; + } + return w; +} + +#endif // QT_NO_SQL diff --git a/main/dependencies/qt3/src/sql/qsqleditorfactory.h b/main/dependencies/qt3/src/sql/qsqleditorfactory.h new file mode 100644 index 000000000..50c572e1e --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqleditorfactory.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** Definition of QSqlEditorFactory class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLEDITORFACTORY_H +#define QSQLEDITORFACTORY_H + +#ifndef QT_H +#include "qeditorfactory.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL_EDIT_WIDGETS + +class QSqlField; + +class QM_EXPORT_SQL QSqlEditorFactory : public QEditorFactory +{ +public: + QSqlEditorFactory ( QObject * parent = 0, const char * name = 0 ); + ~QSqlEditorFactory(); + virtual QWidget * createEditor( QWidget * parent, const QVariant & variant ); + virtual QWidget * createEditor( QWidget * parent, const QSqlField * field ); + + static QSqlEditorFactory * defaultFactory(); + static void installDefaultFactory( QSqlEditorFactory * factory ); + +private: +#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator= + QSqlEditorFactory( const QSqlEditorFactory & ); + QSqlEditorFactory &operator=( const QSqlEditorFactory & ); +#endif +}; + +#endif // QT_NO_SQL +#endif // QSQLEDITORFACTORY_H diff --git a/main/dependencies/qt3/src/sql/qsqlerror.cpp b/main/dependencies/qt3/src/sql/qsqlerror.cpp new file mode 100644 index 000000000..137be84d9 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlerror.cpp @@ -0,0 +1,228 @@ +/**************************************************************************** +** +** Implementation of QSqlError class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlerror.h" +#include <qmessagebox.h> + +#ifndef QT_NO_SQL + +/*! + \class QSqlError qsqlerror.h + \brief The QSqlError class provides SQL database error information. + + \ingroup database + \module sql + + This class is used to report database-specific errors. An error + description and (if appropriate) a database-specific error number + can be obtained using this class. +*/ + +/*! + \enum QSqlError::Type + + This enum type describes the type of SQL error that occurred. + + \value None no error occurred + \value Connection connection error + \value Statement SQL statement syntax error + \value Transaction transaction failed error + \value Unknown unknown error +*/ + +/*! + 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, + int 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) +{ +} + +/*! + Sets the error equal to \a other. +*/ + +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. +*/ +QString QSqlError::driverText() const +{ + return driverError; +} + +/*! + Sets the driver error text to the value of \a driverText. +*/ + +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. +*/ + +QString QSqlError::databaseText() const +{ + return databaseError; +} + +/*! + Sets the database error text to the value of \a databaseText. +*/ + +void QSqlError::setDatabaseText( const QString& databaseText ) +{ + databaseError = databaseText; +} + +/*! + Returns the error type, or -1 if the type cannot be determined. + + \sa QSqlError::Type. +*/ + +int QSqlError::type() const +{ + return errorType; +} + +/*! + Sets the error type to the value of \a type. +*/ + +void QSqlError::setType( int type ) +{ + errorType = type; +} + +/*! + Returns the database-specific error number, or -1 if it cannot be + determined. +*/ + +int QSqlError::number() const +{ + return errorNumber; +} + +/*! + Sets the database-specific error number to \a number. +*/ + +void QSqlError::setNumber( int number ) +{ + errorNumber = number; +} + +/*! + This is a convenience function that returns databaseText() and + driverText() concatenated into a single string. + + \sa showMessage(), driverText(), databaseText() +*/ + +QString QSqlError::text() const +{ + if ( databaseError.endsWith("\n") ) + return databaseError + driverError; + else + return databaseError + " " + driverError; +} + +/*! + \obsolete + + This is a convenience function that pops up a QMessageBox + containing the message returned by text(). An additional string + can be passed in via the \a msg parameter, which will be + concatenated with the text() message. + + \sa text(), driverText(), databaseText() +*/ +void QSqlError::showMessage( const QString& msg ) const +{ +#ifndef QT_NO_MESSAGEBOX + QMessageBox::warning( NULL, "SQL Error", msg + text(), + QMessageBox::Ok, QMessageBox::NoButton ); +#endif // QT_NO_MESSAGEBOX +} +#endif // QT_NO_SQL diff --git a/main/dependencies/qt3/src/sql/qsqlerror.h b/main/dependencies/qt3/src/sql/qsqlerror.h new file mode 100644 index 000000000..addbd7155 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlerror.h @@ -0,0 +1,93 @@ +/**************************************************************************** +** +** Definition of QSqlError class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLERROR_H +#define QSQLERROR_H + +#ifndef QT_H +#include "qstring.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL + +class QM_EXPORT_SQL QSqlError +{ +public: + enum Type { + None, + Connection, + Statement, + Transaction, + Unknown + }; + QSqlError( const QString& driverText = QString::null, + const QString& databaseText = QString::null, + int type = QSqlError::None, + int number = -1 ); + QSqlError( const QSqlError& other ); + QSqlError& operator=( const QSqlError& other ); + virtual ~QSqlError(); + + QString driverText() const; + virtual void setDriverText( const QString& driverText ); + QString databaseText() const; + virtual void setDatabaseText( const QString& databaseText ); + int type() const; + virtual void setType( int type ); + int number() const; + virtual void setNumber( int number ); + QString text() const; + void showMessage( const QString& msg = QString::null ) const; + +private: + QString driverError; + QString databaseError; + int errorType; + int errorNumber; +}; + +#endif // QT_NO_SQL +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlextension_p.cpp b/main/dependencies/qt3/src/sql/qsqlextension_p.cpp new file mode 100644 index 000000000..4e68fee5c --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlextension_p.cpp @@ -0,0 +1,169 @@ +/**************************************************************************** +** +** Implementation of the QSqlExtension class +** +** Created : 2002-06-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlextension_p.h" + +#ifndef QT_NO_SQL +QSqlExtension::QSqlExtension() + : bindm( BindByPosition ), bindCount( 0 ) +{ +} + +QSqlExtension::~QSqlExtension() +{ +} + +bool QSqlExtension::prepare( const QString& /*query*/ ) +{ + return FALSE; +} + +bool QSqlExtension::exec() +{ + return FALSE; +} + +void QSqlExtension::bindValue( const QString& placeholder, const QVariant& val, QSql::ParameterType tp ) +{ + bindm = BindByName; + // if the index has already been set when doing emulated named + // bindings - don't reset it + if ( index.contains( (int)values.count() ) ) { + index[ (int)values.count() ] = placeholder; + } + values[ placeholder ] = Param( val, tp ); +} + +void QSqlExtension::bindValue( int pos, const QVariant& val, QSql::ParameterType tp ) +{ + bindm = BindByPosition; + index[ pos ] = QString::number( pos ); + QString nm = QString::number( pos ); + values[ nm ] = Param( val, tp ); +} + +void QSqlExtension::addBindValue( const QVariant& val, QSql::ParameterType tp ) +{ + bindm = BindByPosition; + bindValue( bindCount++, val, tp ); +} + +void QSqlExtension::clearValues() +{ + values.clear(); + bindCount = 0; +} + +void QSqlExtension::resetBindCount() +{ + bindCount = 0; +} + +void QSqlExtension::clearIndex() +{ + index.clear(); + holders.clear(); +} + +void QSqlExtension::clear() +{ + clearValues(); + clearIndex(); +} + +QVariant QSqlExtension::parameterValue( const QString& holder ) +{ + return values[ holder ].value; +} + +QVariant QSqlExtension::parameterValue( int pos ) +{ + return values[ index[ pos ] ].value; +} + +QVariant QSqlExtension::boundValue( const QString& holder ) const +{ + return values[ holder ].value; +} + +QVariant QSqlExtension::boundValue( int pos ) const +{ + return values[ index[ pos ] ].value; +} + +QMap<QString, QVariant> QSqlExtension::boundValues() const +{ + QMap<QString, Param>::ConstIterator it; + QMap<QString, QVariant> m; + if ( bindm == BindByName ) { + for ( it = values.begin(); it != values.end(); ++it ) + m.insert( it.key(), it.data().value ); + } else { + QString key, tmp, fmt; + fmt.sprintf( "%%0%dd", QString::number( values.count()-1 ).length() ); + for ( it = values.begin(); it != values.end(); ++it ) { + tmp.sprintf( fmt.ascii(), it.key().toInt() ); + m.insert( tmp, it.data().value ); + } + } + return m; +} + +QSqlExtension::BindMethod QSqlExtension::bindMethod() +{ + return bindm; +} + +QSqlDriverExtension::QSqlDriverExtension() +{ +} + +QSqlDriverExtension::~QSqlDriverExtension() +{ +} + +QSqlOpenExtension::QSqlOpenExtension() +{ +} + +QSqlOpenExtension::~QSqlOpenExtension() +{ +} +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlextension_p.h b/main/dependencies/qt3/src/sql/qsqlextension_p.h new file mode 100644 index 000000000..01e540e7a --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlextension_p.h @@ -0,0 +1,148 @@ +/**************************************************************************** +** +** Definition of the QSqlExtension class +** +** Created : 2002-06-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLEXTENSION_P_H +#define QSQLEXTENSION_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. +// +// + +#ifndef QT_H +#include "qmap.h" +#include "qvaluevector.h" +#include "qstring.h" +#include "qvariant.h" +#include "qsql.h" +#endif // QT_H + +#ifndef QT_NO_SQL + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#define QM_TEMPLATE_EXTERN_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#define QM_TEMPLATE_EXTERN_SQL Q_TEMPLATE_EXTERN +#endif + +struct Param { + Param( const QVariant& v = QVariant(), QSql::ParameterType t = QSql::In ): value( v ), typ( t ) {} + QVariant value; + QSql::ParameterType typ; + Q_DUMMY_COMPARISON_OPERATOR(Param) +}; + +struct Holder { + Holder( const QString& hldr = QString::null, int pos = -1 ): holderName( hldr ), holderPos( pos ) {} + bool operator==( const Holder& h ) const { return h.holderPos == holderPos && h.holderName == holderName; } + bool operator!=( const Holder& h ) const { return h.holderPos != holderPos || h.holderName != holderName; } + QString holderName; + int holderPos; +}; + +#define Q_DEFINED_QSQLEXTENSION +#include "qwinexport.h" + +class QM_EXPORT_SQL QSqlExtension { +public: + QSqlExtension(); + virtual ~QSqlExtension(); + virtual bool prepare( const QString& query ); + virtual bool exec(); + virtual void bindValue( const QString& holder, const QVariant& value, QSql::ParameterType = QSql::In ); + virtual void bindValue( int pos, const QVariant& value, QSql::ParameterType = QSql::In ); + virtual void addBindValue( const QVariant& value, QSql::ParameterType = QSql::In ); + virtual QVariant parameterValue( const QString& holder ); + virtual QVariant parameterValue( int pos ); + QVariant boundValue( const QString& holder ) const; + QVariant boundValue( int pos ) const; + QMap<QString, QVariant> boundValues() const; + void clear(); + void clearValues(); + void clearIndex(); + void resetBindCount(); + + enum BindMethod { BindByPosition, BindByName }; + BindMethod bindMethod(); // ### 4.0: make this const + BindMethod bindm; + int bindCount; + + QMap<int, QString> index; + typedef QMap<QString, Param> ValueMap; + ValueMap values; + + // convenience container for QSqlQuery + // to map holders <-> positions + typedef QValueVector<Holder> HolderVector; + HolderVector holders; +}; + +class QM_EXPORT_SQL QSqlDriverExtension +{ +public: + QSqlDriverExtension(); + virtual ~QSqlDriverExtension(); + virtual bool isOpen() const = 0; +}; + +class QM_EXPORT_SQL QSqlOpenExtension +{ +public: + QSqlOpenExtension(); + virtual ~QSqlOpenExtension(); + virtual bool open( const QString& db, + const QString& user, + const QString& password, + const QString& host, + int port, + const QString& connOpts ) = 0; +}; +#endif + +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlfield.cpp b/main/dependencies/qt3/src/sql/qsqlfield.cpp new file mode 100644 index 000000000..bf66011c1 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlfield.cpp @@ -0,0 +1,563 @@ +/**************************************************************************** +** +** Implementation of QSqlField class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlfield.h" + +#ifndef QT_NO_SQL + + +/*! + \class QSqlField qsqlfield.h + \brief The QSqlField class manipulates the fields in SQL database tables + and views. + + \ingroup database + \module sql + + 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: + + \code + QSqlField f( "myfield", QVariant::Int ); + f.setValue( QPixmap() ); // will not work + \endcode + + However, the field will attempt to cast certain data types to the + field data type where possible: + + \code + QSqlField f( "myfield", QVariant::Int ); + f.setValue( QString("123") ); // casts QString to int + \endcode + + QSqlField objects are rarely created explicitly in application + code. They are usually accessed indirectly through \l QSqlRecord + or \l QSqlCursor which already contain a list of fields. For + example: + + \code + QSqlCursor cur( "Employee" ); // create cursor using the 'Employee' table + QSqlField* f = cur.field( "name" ); // use the 'name' field + f->setValue( "Dave" ); // set field value + ... + \endcode + + In practice we rarely need to extract a pointer to a field at all. + The previous example would normally be written: + + \code + QSqlCursor cur( "Employee" ); + cur.setValue( "name", "Dave" ); + ... + \endcode +*/ + +/*! + Constructs an empty field called \a fieldName of type \a type. +*/ + +QSqlField::QSqlField( const QString& fieldName, QVariant::Type type ) + : nm(fieldName), ro(FALSE), nul(FALSE) +{ + d = new QSqlFieldPrivate(); + d->type = type; + val.cast( type ); +} + +/*! + Constructs a copy of \a other. +*/ + +QSqlField::QSqlField( const QSqlField& other ) + : nm( other.nm ), val( other.val ), ro( other.ro ), nul( other.nul ) +{ + d = new QSqlFieldPrivate(); + d->type = other.d->type; +} + +/*! + Sets the field equal to \a other. +*/ + +QSqlField& QSqlField::operator=( const QSqlField& other ) +{ + nm = other.nm; + val = other.val; + ro = other.ro; + nul = other.nul; + d->type = other.d->type; + return *this; +} + +/*! + Returns TRUE if the field is equal to \a other; otherwise returns + FALSE. Fields are considered equal when the following field + properties are the same: + + \list + \i \c name() + \i \c isNull() + \i \c value() + \i \c isReadOnly() + \endlist + +*/ +bool QSqlField::operator==(const QSqlField& other) const +{ + return ( nm == other.nm && + val == other.val && + ro == other.ro && + nul == other.nul && + d->type == other.d->type ); +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QSqlField::~QSqlField() +{ + delete d; +} + + +/*! + \fn QVariant QSqlField::value() const + + Returns the value of the field as a QVariant. +*/ + +/*! + 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. For example: + + \code + QSqlCursor cur( "Employee" ); // 'Employee' table + QSqlField* f = cur.field( "student_count" ); // an integer field + ... + f->setValue( myLineEdit->text() ); // cast the line edit text to an integer + \endcode + + \sa isReadOnly() +*/ + +void QSqlField::setValue( const QVariant& value ) +{ + if ( isReadOnly() ) + return; + if ( value.type() != d->type ) { + if ( !val.canCast( d->type ) ) + qWarning("QSqlField::setValue: %s cannot cast from %s to %s", + nm.local8Bit().data(), value.typeName(), QVariant::typeToName( d->type ) ); + } + val = value; + + if ( value.isNull() ) + nul = TRUE; + else + nul = val.type() == QVariant::Invalid; +} + +/*! + Clears the value of the field. If the field is read-only, nothing + happens. If \a nullify is TRUE (the default), the field is set to + NULL. +*/ + +void QSqlField::clear( bool nullify ) +{ + if ( isReadOnly() ) + return; + QVariant v; + v.cast( type() ); + val = v; + if ( nullify ) + nul = TRUE; +} + +/*! + \fn void QSqlField::setName( const QString& name ) + + Sets the name of the field to \a name. +*/ + +void QSqlField::setName( const QString& name ) +{ + nm = name; +} + +/*! + \fn void QSqlField::setNull() + + Sets the field to NULL and clears the value using clear(). If the + field is read-only, nothing happens. + + \sa isReadOnly() clear() +*/ + +void QSqlField::setNull() +{ + clear( TRUE ); +} + +/*! + \fn void QSqlField::setReadOnly( bool readOnly ) + + Sets the read only flag of the field's value to \a readOnly. + + \sa setValue() +*/ +void QSqlField::setReadOnly( bool readOnly ) +{ + ro = readOnly; +} + +/*! + \fn QString QSqlField::name() const + + Returns the name of the field. +*/ + +/*! + \fn QVariant::Type QSqlField::type() const + + 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. +*/ + +/*! + \fn bool QSqlField::isReadOnly() const + + Returns TRUE if the field's value is read only; otherwise returns + FALSE. +*/ + +/*! + \fn bool QSqlField::isNull() const + + Returns TRUE if the field is currently NULL; otherwise returns + FALSE. +*/ + + +/******************************************/ +/******* QSqlFieldInfo Impl ******/ +/******************************************/ + +struct QSqlFieldInfoPrivate +{ + int required, len, prec, typeID; + uint generated: 1; + uint trim: 1; + uint calculated: 1; + QString name; + QString typeName; + QVariant::Type typ; + QVariant defValue; +}; + +/*! + \class QSqlFieldInfo qsqlfield.h + \brief The QSqlFieldInfo class stores meta data associated with a SQL field. + + \ingroup database + \module sql + + QSqlFieldInfo objects only store meta data; field values are + stored in QSqlField objects. + + All values must be set in the constructor, and may be retrieved + using isRequired(), type(), length(), precision(), defaultValue(), + name(), isGenerated() and typeID(). +*/ + +/*! + Constructs a QSqlFieldInfo with the following parameters: + \table + \row \i \a name \i the name of the field. + \row \i \a typ \i the field's type in a QVariant. + \row \i \a required \i greater than 0 if the field is required, 0 + if its value can be NULL and less than 0 if it cannot be + determined whether the field is required or not. + \row \i \a len \i the length of the field. Note that for + non-character types some databases return either the length in + bytes or the number of digits. -1 signifies that the length cannot + be determined. + \row \i \a prec \i the precision of the field, or -1 if the field + has no precision or it cannot be determined. + \row \i \a defValue \i the default value that is inserted into + the table if none is specified by the user. QVariant() if there is + no default value or it cannot be determined. + \row \i \a typeID \i the internal typeID of the database system + (only useful for low-level programming). 0 if unknown. + \row \i \a generated \i TRUE indicates that this field should be + included in auto-generated SQL statments, e.g. in QSqlCursor. + \row \i \a trim \i TRUE indicates that widgets should remove + trailing whitespace from character fields. This does not affect + the field value but only its representation inside widgets. + \row \i \a calculated \i TRUE indicates that the value of this + field is calculated. The value of calculated fields can by + modified by subclassing QSqlCursor and overriding + QSqlCursor::calculateField(). + \endtable +*/ +QSqlFieldInfo::QSqlFieldInfo( const QString& name, + QVariant::Type typ, + int required, + int len, + int prec, + const QVariant& defValue, + int typeID, + bool generated, + bool trim, + bool calculated ) +{ + d = new QSqlFieldInfoPrivate(); + d->name = name; + d->typ = typ; + d->required = required; + d->len = len; + d->prec = prec; + d->defValue = defValue; + d->typeID = typeID; + d->generated = generated; + d->trim = trim; + d->calculated = calculated; +} + +/*! + Constructs a copy of \a other. +*/ +QSqlFieldInfo::QSqlFieldInfo( const QSqlFieldInfo & other ) +{ + d = new QSqlFieldInfoPrivate( *(other.d) ); +} + +/*! + Creates a QSqlFieldInfo object with the type and the name of the + QSqlField \a other. If \a generated is TRUE this field will be + included in auto-generated SQL statments, e.g. in QSqlCursor. +*/ +QSqlFieldInfo::QSqlFieldInfo( const QSqlField & other, bool generated ) +{ + d = new QSqlFieldInfoPrivate(); + d->name = other.name(); + d->typ = other.type(); + d->required = -1; + d->len = -1; + d->prec = -1; + d->typeID = 0; + d->generated = generated; + d->trim = FALSE; + d->calculated = FALSE; +} + +/*! + Destroys the object and frees any allocated resources. +*/ +QSqlFieldInfo::~QSqlFieldInfo() +{ + delete d; +} + +/*! + Assigns \a other to this field info and returns a reference to it. +*/ +QSqlFieldInfo& QSqlFieldInfo::operator=( const QSqlFieldInfo& other ) +{ + delete d; + d = new QSqlFieldInfoPrivate( *(other.d) ); + return *this; +} + +/*! + Returns TRUE if this fieldinfo is equal to \a f; otherwise returns + FALSE. + + Two field infos are considered equal if all their attributes + match. +*/ +bool QSqlFieldInfo::operator==( const QSqlFieldInfo& f ) const +{ + return ( d->name == f.d->name && + d->typ == f.d->typ && + d->required == f.d->required && + d->len == f.d->len && + d->prec == f.d->prec && + d->defValue == f.d->defValue && + d->typeID == f.d->typeID && + d->generated == f.d->generated && + d->trim == f.d->trim && + d->calculated == f.d->calculated ); +} + +/*! + Returns an empty QSqlField based on the information in this + QSqlFieldInfo. +*/ +QSqlField QSqlFieldInfo::toField() const +{ return QSqlField( d->name, d->typ ); } + +/*! + Returns a value greater than 0 if the field is required (NULL + values are not allowed), 0 if it isn't required (NULL values are + allowed) or less than 0 if it cannot be determined whether the + field is required or not. +*/ +int QSqlFieldInfo::isRequired() const +{ return d->required; } + +/*! + Returns the field's type or QVariant::Invalid if the type is + unknown. +*/ +QVariant::Type QSqlFieldInfo::type() const +{ return d->typ; } + +/*! + Returns the field's length. For fields storing text the return + value is the maximum number of characters the field can hold. For + non-character fields some database systems return the number of + bytes needed or the number of digits allowed. If the length cannot + be determined -1 is returned. +*/ +int QSqlFieldInfo::length() const +{ return d->len; } + +/*! + Returns the field's precision or -1 if the field has no precision + or it cannot be determined. +*/ +int QSqlFieldInfo::precision() const +{ return d->prec; } + +/*! + Returns the field's default value or an empty QVariant if the + field has no default value or the value couldn't be determined. + The default value is the value inserted in the database when it + is not explicitly specified by the user. +*/ +QVariant QSqlFieldInfo::defaultValue() const +{ return d->defValue; } + +/*! + Returns the name of the field in the SQL table. +*/ +QString QSqlFieldInfo::name() const +{ return d->name; } + +/*! + Returns the internal type identifier as returned from the database + system. The return value is 0 if the type is unknown. + + \warning This information is only useful for low-level database + programming and is \e not database independent. +*/ +int QSqlFieldInfo::typeID() const +{ return d->typeID; } + +/*! + Returns TRUE if the field should be included in auto-generated + SQL statments, e.g. in QSqlCursor; otherwise returns FALSE. + + \sa setGenerated() +*/ +bool QSqlFieldInfo::isGenerated() const +{ return d->generated; } + +/*! + Returns TRUE if trailing whitespace should be removed from + character fields; otherwise returns FALSE. + + \sa setTrim() +*/ +bool QSqlFieldInfo::isTrim() const +{ return d->trim; } + +/*! + Returns TRUE if the field is calculated; otherwise returns FALSE. + + \sa setCalculated() +*/ +bool QSqlFieldInfo::isCalculated() const +{ return d->calculated; } + +/*! + If \a trim is TRUE widgets should remove trailing whitespace from + character fields. This does not affect the field value but only + its representation inside widgets. + + \sa isTrim() +*/ +void QSqlFieldInfo::setTrim( bool trim ) +{ d->trim = trim; } + +/*! + \a gen set to FALSE indicates that this field should not appear + in auto-generated SQL statements (for example in QSqlCursor). + + \sa isGenerated() +*/ +void QSqlFieldInfo::setGenerated( bool gen ) +{ d->generated = gen; } + +/*! + \a calc set to TRUE indicates that this field is a calculated + field. The value of calculated fields can by modified by subclassing + QSqlCursor and overriding QSqlCursor::calculateField(). + + \sa isCalculated() +*/ +void QSqlFieldInfo::setCalculated( bool calc ) +{ d->calculated = calc; } + +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlfield.h b/main/dependencies/qt3/src/sql/qsqlfield.h new file mode 100644 index 000000000..b9e312b06 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlfield.h @@ -0,0 +1,154 @@ +/**************************************************************************** +** +** Definition of QSqlField class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLFIELD_H +#define QSQLFIELD_H + +#ifndef QT_H +#include "qstring.h" +#include "qvariant.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL + +class QSqlFieldPrivate +{ +public: + QVariant::Type type; +}; + +class QM_EXPORT_SQL QSqlField +{ +public: + QSqlField( const QString& fieldName = QString::null, QVariant::Type type = QVariant::Invalid ); + QSqlField( const QSqlField& other ); + QSqlField& operator=( const QSqlField& other ); + bool operator==(const QSqlField& other) const; + virtual ~QSqlField(); + + virtual void setValue( const QVariant& value ); + virtual QVariant value() const; + virtual void setName( const QString& name ); + QString name() const; + virtual void setNull(); + bool isNull() const; + virtual void setReadOnly( bool readOnly ); + bool isReadOnly() const; + void clear( bool nullify = TRUE ); + QVariant::Type type() const; + +private: + QString nm; + QVariant val; + uint ro: 1; + uint nul: 1; + QSqlFieldPrivate* d; +}; + +inline QVariant QSqlField::value() const +{ return val; } + +inline QString QSqlField::name() const +{ return nm; } + +inline bool QSqlField::isNull() const +{ return nul; } + +inline bool QSqlField::isReadOnly() const +{ return ro; } + +inline QVariant::Type QSqlField::type() const +{ return d->type; } + + +/******************************************/ +/******* QSqlFieldInfo Class ******/ +/******************************************/ + +struct QSqlFieldInfoPrivate; + +class QM_EXPORT_SQL QSqlFieldInfo +{ +public: + QSqlFieldInfo( const QString& name = QString::null, + QVariant::Type typ = QVariant::Invalid, + int required = -1, + int len = -1, + int prec = -1, + const QVariant& defValue = QVariant(), + int sqlType = 0, + bool generated = TRUE, + bool trim = FALSE, + bool calculated = FALSE ); + QSqlFieldInfo( const QSqlFieldInfo & other ); + QSqlFieldInfo( const QSqlField & other, bool generated = TRUE ); + virtual ~QSqlFieldInfo(); + QSqlFieldInfo& operator=( const QSqlFieldInfo& other ); + bool operator==( const QSqlFieldInfo& f ) const; + + QSqlField toField() const; + int isRequired() const; + QVariant::Type type() const; + int length() const; + int precision() const; + QVariant defaultValue() const; + QString name() const; + int typeID() const; + bool isGenerated() const; + bool isTrim() const; + bool isCalculated() const; + + virtual void setTrim( bool trim ); + virtual void setGenerated( bool gen ); + virtual void setCalculated( bool calc ); + +private: + QSqlFieldInfoPrivate* d; +}; + + +#endif // QT_NO_SQL +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlform.cpp b/main/dependencies/qt3/src/sql/qsqlform.cpp new file mode 100644 index 000000000..255c5d7e5 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlform.cpp @@ -0,0 +1,403 @@ +/**************************************************************************** +** +** Implementation of QSqlForm class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlform.h" + +#ifndef QT_NO_SQL_FORM + +#include "qsqlfield.h" +#include "qsqlpropertymap.h" +#include "qsqlrecord.h" +#include "qstringlist.h" +#include "qwidget.h" +#include "qdict.h" + +class QSqlFormPrivate +{ +public: + QSqlFormPrivate() : propertyMap( 0 ), buf( 0 ), dirty( FALSE ) {} + ~QSqlFormPrivate() { if ( propertyMap ) delete propertyMap; } + QStringList fld; + QDict<QWidget> wgt; + QMap< QWidget *, QSqlField * > map; + QSqlPropertyMap * propertyMap; + QSqlRecord* buf; + bool dirty; +}; + +/*! + \class QSqlForm + \brief The QSqlForm class creates and manages data entry forms + tied to SQL databases. + + \ingroup database + \mainclass + \module sql + + Typical use of a QSqlForm consists of the following steps: + \list + \i Create the widgets you want to appear in the form. + \i Create a cursor and navigate to the record to be edited. + \i Create the QSqlForm. + \i Set the form's record buffer to the cursor's update buffer. + \i Insert each widget and the field it is to edit into the form. + \i Use readFields() to update the editor widgets with values from + the database's fields. + \i Display the form and let the user edit values etc. + \i Use writeFields() to update the database's field values with + the values in the editor widgets. + \endlist + + Note that a QSqlForm does not access the database directly, but + most often via QSqlFields which are part of a QSqlCursor. A + QSqlCursor::insert(), QSqlCursor::update() or QSqlCursor::del() + call is needed to actually write values to the database. + + Some sample code to initialize a form successfully: + + \code + QLineEdit myEditor( this ); + QSqlForm myForm( this ); + QSqlCursor myCursor( "mytable" ); + + // Execute a query to make the cursor valid + myCursor.select(); + // Move the cursor to a valid record (the first record) + myCursor.next(); + // Set the form's record pointer to the cursor's edit buffer (which + // contains the current record's values) + myForm.setRecord( myCursor.primeUpdate() ); + + // Insert a field into the form that uses myEditor to edit the + // field 'somefield' in 'mytable' + myForm.insert( &myEditor, "somefield" ); + + // Update myEditor with the value from the mapped database field + myForm.readFields(); + ... + // Let the user edit the form + ... + // Update the database + myForm.writeFields(); // Update the cursor's edit buffer from the form + myCursor.update(); // Update the database from the cursor's buffer + \endcode + + If you want to use custom editors for displaying and editing data + fields, you must install a custom QSqlPropertyMap. The form + uses this object to get or set the value of a widget. + + Note that \link designer-manual.book Qt Designer\endlink provides + a visual means of creating data-aware forms. + + \sa installPropertyMap(), QSqlPropertyMap +*/ + + +/*! + Constructs a QSqlForm with parent \a parent and called \a name. +*/ +QSqlForm::QSqlForm( QObject * parent, const char * name ) + : QObject( parent, name ) +{ + d = new QSqlFormPrivate(); +} + +/*! + Destroys the object and frees any allocated resources. +*/ +QSqlForm::~QSqlForm() +{ + delete d; +} + +/*! + Installs a custom QSqlPropertyMap. This is useful if you plan to + create your own custom editor widgets. + + QSqlForm takes ownership of \a pmap, so \a pmap is deleted when + QSqlForm goes out of scope. + + \sa QDataTable::installEditorFactory() +*/ +void QSqlForm::installPropertyMap( QSqlPropertyMap * pmap ) +{ + if( d->propertyMap ) + delete d->propertyMap; + d->propertyMap = pmap; +} + +/*! + Sets \a buf as the record buffer for the form. To force the + display of the data from \a buf, use readFields(). + + \sa readFields() writeFields() +*/ + +void QSqlForm::setRecord( QSqlRecord* buf ) +{ + d->dirty = TRUE; + d->buf = buf; +} + +/*! + Inserts a \a widget, and the name of the \a field it is to be + mapped to, into the form. To actually associate inserted widgets + with an edit buffer, use setRecord(). + + \sa setRecord() +*/ + +void QSqlForm::insert( QWidget * widget, const QString& field ) +{ + d->dirty = TRUE; + d->wgt.insert( field, widget ); + d->fld += field; +} + +/*! + \overload + + Removes \a field from the form. +*/ + +void QSqlForm::remove( const QString& field ) +{ + d->dirty = TRUE; + if ( d->fld.find( field ) != d->fld.end() ) + d->fld.remove( d->fld.find( field ) ); + d->wgt.remove( field ); +} + +/*! + \overload + + Inserts a \a widget, and the \a field it is to be mapped to, into + the form. +*/ + +void QSqlForm::insert( QWidget * widget, QSqlField * field ) +{ + d->map[widget] = field; +} + +/*! + Removes a \a widget, and hence the field it's mapped to, from the + form. +*/ + +void QSqlForm::remove( QWidget * widget ) +{ + d->map.remove( widget ); +} + +/*! + Clears the values in all the widgets, and the fields they are + mapped to, in the form. If \a nullify is TRUE (the default is + FALSE), each field is also set to NULL. +*/ +void QSqlForm::clearValues( bool nullify ) +{ + QMap< QWidget *, QSqlField * >::Iterator it; + for( it = d->map.begin(); it != d->map.end(); ++it ){ + QSqlField* f = (*it); + if ( f ) + f->clear( nullify ); + } + readFields(); +} + +/*! + Removes every widget, and the fields they're mapped to, from the form. +*/ +void QSqlForm::clear() +{ + d->dirty = TRUE; + d->fld.clear(); + clearMap(); +} + +/*! + Returns the number of widgets in the form. +*/ +uint QSqlForm::count() const +{ + return (uint)d->map.count(); +} + +/*! + Returns the \a{i}-th widget in the form. Useful for traversing + the widgets in the form. +*/ +QWidget * QSqlForm::widget( uint i ) const +{ + QMap< QWidget *, QSqlField * >::ConstIterator it; + uint cnt = 0; + + if( i > d->map.count() ) return 0; + for( it = d->map.begin(); it != d->map.end(); ++it ){ + if( cnt++ == i ) + return it.key(); + } + return 0; +} + +/*! + Returns the widget that field \a field is mapped to. +*/ +QWidget * QSqlForm::fieldToWidget( QSqlField * field ) const +{ + QMap< QWidget *, QSqlField * >::ConstIterator it; + for( it = d->map.begin(); it != d->map.end(); ++it ){ + if( *it == field ) + return it.key(); + } + return 0; +} + +/*! + Returns the SQL field that widget \a widget is mapped to. +*/ +QSqlField * QSqlForm::widgetToField( QWidget * widget ) const +{ + if( d->map.contains( widget ) ) + return d->map[widget]; + else + return 0; +} + +/*! + Updates the widgets in the form with current values from the SQL + fields they are mapped to. +*/ +void QSqlForm::readFields() +{ + sync(); + QSqlField * f; + QMap< QWidget *, QSqlField * >::Iterator it; + QSqlPropertyMap * pmap = (d->propertyMap == 0) ? + QSqlPropertyMap::defaultMap() : d->propertyMap; + for(it = d->map.begin() ; it != d->map.end(); ++it ){ + f = widgetToField( it.key() ); + if( !f ) + continue; + pmap->setProperty( it.key(), f->value() ); + } +} + +/*! + Updates the SQL fields with values from the widgets they are + mapped to. To actually update the database with the contents of + the record buffer, use QSqlCursor::insert(), QSqlCursor::update() + or QSqlCursor::del() as appropriate. +*/ +void QSqlForm::writeFields() +{ + sync(); + QSqlField * f; + QMap< QWidget *, QSqlField * >::Iterator it; + QSqlPropertyMap * pmap = (d->propertyMap == 0) ? + QSqlPropertyMap::defaultMap() : d->propertyMap; + + for(it = d->map.begin() ; it != d->map.end(); ++it ){ + f = widgetToField( it.key() ); + if( !f ) + continue; + f->setValue( pmap->property( it.key() ) ); + } +} + +/*! + Updates the widget \a widget with the value from the SQL field it + is mapped to. Nothing happens if no SQL field is mapped to the \a + widget. +*/ +void QSqlForm::readField( QWidget * widget ) +{ + sync(); + QSqlField * field = 0; + QSqlPropertyMap * pmap = (d->propertyMap == 0) ? + QSqlPropertyMap::defaultMap() : d->propertyMap; + field = widgetToField( widget ); + if( field ) + pmap->setProperty( widget, field->value() ); +} + +/*! + Updates the SQL field with the value from the \a widget it is + mapped to. Nothing happens if no SQL field is mapped to the \a + widget. +*/ +void QSqlForm::writeField( QWidget * widget ) +{ + sync(); + QSqlField * field = 0; + QSqlPropertyMap * pmap = (d->propertyMap == 0) ? + QSqlPropertyMap::defaultMap() : d->propertyMap; + field = widgetToField( widget ); + if( field ) + field->setValue( pmap->property( widget ) ); +} + +/*! \internal +*/ + +void QSqlForm::sync() +{ + if ( d->dirty ) { + clearMap(); + if ( d->buf ) { + for ( uint i = 0; i < d->fld.count(); ++i ) + insert( d->wgt[ d->fld[ i ] ], d->buf->field( d->fld[ i ] ) ); + } + } + d->dirty = FALSE; +} + +/*! \internal + + Clears the internal map of widget/field associations +*/ + +void QSqlForm::clearMap() +{ + d->map.clear(); +} + +#endif // QT_NO_SQL diff --git a/main/dependencies/qt3/src/sql/qsqlform.h b/main/dependencies/qt3/src/sql/qsqlform.h new file mode 100644 index 000000000..5ab070ebc --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlform.h @@ -0,0 +1,108 @@ +/**************************************************************************** +** +** Definition of QSqlForm class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLFORM_H +#define QSQLFORM_H + +#ifndef QT_H +#include "qobject.h" +#include "qmap.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL_FORM + +class QSqlField; +class QSqlRecord; +class QSqlEditorFactory; +class QSqlPropertyMap; +class QWidget; +class QSqlFormPrivate; + +class QM_EXPORT_SQL QSqlForm : public QObject +{ + Q_OBJECT +public: + QSqlForm( QObject * parent = 0, const char * name = 0 ); + ~QSqlForm(); + + virtual void insert( QWidget * widget, const QString& field ); + virtual void remove( const QString& field ); + uint count() const; + + QWidget * widget( uint i ) const; + QSqlField * widgetToField( QWidget * widget ) const; + QWidget * fieldToWidget( QSqlField * field ) const; + + void installPropertyMap( QSqlPropertyMap * map ); + + virtual void setRecord( QSqlRecord* buf ); + +public slots: + virtual void readField( QWidget * widget ); + virtual void writeField( QWidget * widget ); + virtual void readFields(); + virtual void writeFields(); + + virtual void clear(); + virtual void clearValues( bool nullify = FALSE ); + +protected: + virtual void insert( QWidget * widget, QSqlField * field ); + virtual void remove( QWidget * widget ); + void clearMap(); + +private: + virtual void sync(); + QSqlFormPrivate* d; + +#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator= + QSqlForm( const QSqlForm & ); + QSqlForm &operator=( const QSqlForm & ); +#endif +}; + +#endif // QT_NO_SQL +#endif // QSQLFORM_H diff --git a/main/dependencies/qt3/src/sql/qsqlindex.cpp b/main/dependencies/qt3/src/sql/qsqlindex.cpp new file mode 100644 index 000000000..f5bdacedf --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlindex.cpp @@ -0,0 +1,301 @@ +/**************************************************************************** +** +** Implementation of QSqlIndex class +** +** Created : 2000-11-03 +** +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlindex.h" + +#ifndef QT_NO_SQL + +#include "qsqlcursor.h" + +/*! + \class QSqlIndex qsqlindex.h + \brief The QSqlIndex class provides functions to manipulate and + describe QSqlCursor and QSqlDatabase indexes. + + \ingroup database + \module sql + + This class is used to describe and manipulate QSqlCursor and + QSqlDatabase indexes. An 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, or to affect the + behavior of a \l QSqlCursor object. + + Normally, QSqlIndex objects are created by \l QSqlDatabase or + QSqlCursor. +*/ + +/*! + Constructs an empty index using the cursor name \a cursorname and + index name \a name. +*/ + +QSqlIndex::QSqlIndex( const QString& cursorname, const QString& name ) + : QSqlRecord(), 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 ( sorts.at( i ) != sorts.end() ) + 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 ( sorts.at( i ) != sorts.end() ) + sorts[i] = desc; +} + +/*! + \reimp + + 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 ( uint i = 0; i < count(); ++i ) { + if( comma ) + s += sep + " "; + s += createField( i, prefix, verbose ); + comma = TRUE; + } + return s; +} + +/*! + \reimp + + 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. + \code + QStringList list = myIndex.toStringList(); + QStringList::Iterator it = list.begin(); + while( it != list.end() ) { + myProcessing( *it ); + ++it; + } + \endcode + +*/ +QStringList QSqlIndex::toStringList( const QString& prefix, bool verbose ) const +{ + QStringList s; + for ( uint i = 0; i < count(); ++i ) + s += createField( i, prefix, verbose ); + return s; +} + +/*! \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 + "."; + f += field( i )->name(); + if ( verbose ) + f += " " + QString( ( isDescending( i ) ? "DESC" : "ASC" ) ); + return f; +} + +/*! + Returns an index based on the field descriptions in \a l and the + cursor \a cursor. The field descriptions should be in the same + format that toStringList() produces, for example, a surname field + in the people table might be in one of these forms: "surname", + "surname DESC" or "people.surname ASC". + + \sa toStringList() +*/ + +QSqlIndex QSqlIndex::fromStringList( const QStringList& l, const QSqlCursor* cursor ) +{ + QSqlIndex newSort; + for ( uint i = 0; i < l.count(); ++i ) { + QString f = l[ i ]; + bool desc = FALSE; + if ( f.mid( f.length()-3 ) == "ASC" ) + f = f.mid( 0, f.length()-3 ); + if ( f.mid( f.length()-4 ) == "DESC" ) { + desc = TRUE; + f = f.mid( 0, f.length()-4 ); + } + int dot = f.findRev( '.' ); + if ( dot != -1 ) + f = f.mid( dot+1 ); + const QSqlField* field = cursor->field( f.simplifyWhiteSpace() ); + if ( field ) + newSort.append( *field, desc ); + else + qWarning( "QSqlIndex::fromStringList: unknown field: '%s'", f.latin1()); + } + return newSort; +} + +/*! + \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; +} + +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlindex.h b/main/dependencies/qt3/src/sql/qsqlindex.h new file mode 100644 index 000000000..d4d6b0554 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlindex.h @@ -0,0 +1,99 @@ +/**************************************************************************** +** +** Definition of QSqlIndex class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLINDEX_H +#define QSQLINDEX_H + +#ifndef QT_H +#include "qstring.h" +#include "qstringlist.h" +#include "qsqlfield.h" +#include "qsqlrecord.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#define QM_TEMPLATE_EXTERN_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#define QM_TEMPLATE_EXTERN_SQL Q_TEMPLATE_EXTERN +#endif + +#ifndef QT_NO_SQL + +class QSqlCursor; + +class QM_EXPORT_SQL QSqlIndex : public QSqlRecord +{ +public: + QSqlIndex( const QString& cursorName = QString::null, const QString& name = QString::null ); + QSqlIndex( const QSqlIndex& other ); + ~QSqlIndex(); + QSqlIndex& operator=( const QSqlIndex& other ); + virtual void setCursorName( const QString& cursorName ); + QString cursorName() const { return cursor; } + virtual void setName( const QString& name ); + QString name() const { return nm; } + + void append( const QSqlField& field ); + virtual void append( const QSqlField& field, bool desc ); + + bool isDescending( int i ) const; + virtual void setDescending( int i, bool desc ); + + QString toString( const QString& prefix = QString::null, + const QString& sep = ",", + bool verbose = TRUE ) const; + QStringList toStringList( const QString& prefix = QString::null, + bool verbose = TRUE ) const; + + static QSqlIndex fromStringList( const QStringList& l, const QSqlCursor* cursor ); + +private: + QString createField( int i, const QString& prefix, bool verbose ) const; + QString cursor; + QString nm; + QValueList<bool> sorts; +}; + +#define Q_DEFINED_QSQLINDEX +#include "qwinexport.h" +#endif // QT_NO_SQL +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlmanager_p.cpp b/main/dependencies/qt3/src/sql/qsqlmanager_p.cpp new file mode 100644 index 000000000..68360dc73 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlmanager_p.cpp @@ -0,0 +1,941 @@ +/**************************************************************************** +** +** Implementation of sql manager classes +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlmanager_p.h" + +#ifndef QT_NO_SQL + +#include "qapplication.h" +#include "qwidget.h" +#include "qsqlcursor.h" +#include "qsqlform.h" +#include "qsqldriver.h" +#include "qstring.h" +#include "qmessagebox.h" +#include "qbitarray.h" + +//#define QT_DEBUG_DATAMANAGER + +class QSqlCursorManagerPrivate +{ +public: + QSqlCursorManagerPrivate() + : cur( 0 ), autoDelete( FALSE ) + {} + + QString ftr; + QStringList srt; + QSqlCursor* cur; + bool autoDelete; +}; + +/*! + \class QSqlCursorManager qsqlmanager_p.h + \brief The QSqlCursorManager class manages a database cursor. + + \module sql + + \internal + + This class provides common cursor management functionality. This + includes saving and applying sorts and filters, refreshing (i.e., + re-selecting) the cursor and searching for records within the + cursor. + +*/ + +/*! \internal + + Constructs a cursor manager. + +*/ + +QSqlCursorManager::QSqlCursorManager() +{ + d = new QSqlCursorManagerPrivate; +} + + +/*! \internal + + Destroys the object and frees any allocated resources. + +*/ + +QSqlCursorManager::~QSqlCursorManager() +{ + if ( d->autoDelete ) + delete d->cur; + delete d; +} + +/*! \internal + + Sets the manager's sort to the index \a sort. To apply the new + sort, use refresh(). + + */ + +void QSqlCursorManager::setSort( const QSqlIndex& sort ) +{ + setSort( sort.toStringList() ); +} + +/*! \internal + + Sets the manager's sort to the stringlist \a sort. To apply the + new sort, use refresh(). + + */ + +void QSqlCursorManager::setSort( const QStringList& sort ) +{ + d->srt = sort; +} + +/*! \internal + + Returns the current sort, or an empty stringlist if there is none. + +*/ + +QStringList QSqlCursorManager::sort() const +{ + return d->srt; +} + +/*! \internal + + Sets the manager's filter to the string \a filter. To apply the + new filter, use refresh(). + +*/ + +void QSqlCursorManager::setFilter( const QString& filter ) +{ + d->ftr = filter; +} + +/*! \internal + + Returns the current filter, or an empty string if there is none. + +*/ + +QString QSqlCursorManager::filter() const +{ + return d->ftr; +} + +/*! \internal + + Sets auto-delete to \a enable. If TRUE, the default cursor will + be deleted when necessary. + + \sa autoDelete() +*/ + +void QSqlCursorManager::setAutoDelete( bool enable ) +{ + d->autoDelete = enable; +} + + +/*! \internal + + Returns TRUE if auto-deletion is enabled, otherwise FALSE. + + \sa setAutoDelete() + +*/ + +bool QSqlCursorManager::autoDelete() const +{ + return d->autoDelete; +} + +/*! \internal + + Sets the default cursor used by the manager to \a cursor. If \a + autoDelete is TRUE (the default is FALSE), the manager takes + ownership of the \a cursor pointer, which will be deleted when the + manager is destroyed, or when setCursor() is called again. To + activate the \a cursor use refresh(). + + \sa cursor() + +*/ + +void QSqlCursorManager::setCursor( QSqlCursor* cursor, bool autoDelete ) +{ + if ( d->autoDelete ) + delete d->cur; + d->cur = cursor; + d->autoDelete = autoDelete; +} + +/*! \internal + + Returns a pointer to the default cursor used for navigation, or 0 + if there is no default cursor. + + \sa setCursor() + +*/ + +QSqlCursor* QSqlCursorManager::cursor() const +{ + return d->cur; +} + + +/*! \internal + + Refreshes the manager using the default cursor. The manager's + filter and sort are applied. Returns TRUE on success, FALSE if an + error occurred or there is no current cursor. + + \sa setFilter() setSort() + +*/ + +bool QSqlCursorManager::refresh() +{ + QSqlCursor* cur = cursor(); + if ( !cur ) + return FALSE; + QString currentFilter = d->ftr; + QStringList currentSort = d->srt; + QSqlIndex newSort = QSqlIndex::fromStringList( currentSort, cur ); + return cur->select( currentFilter, newSort ); +} + +/* \internal + + Returns TRUE if the \a buf field values that correspond to \a idx + match the field values in \a cur that correspond to \a idx. +*/ + +static bool index_matches( const QSqlCursor* cur, const QSqlRecord* buf, + const QSqlIndex& idx ) +{ + bool indexEquals = FALSE; + for ( uint i = 0; i < idx.count(); ++i ) { + const QString fn( idx.field(i)->name() ); + if ( cur->value( fn ) == buf->value( fn ) ) + indexEquals = TRUE; + else { + indexEquals = FALSE; + break; + } + } + return indexEquals; +} + +/* + Return less than, equal to or greater than 0 if buf1 is less than, + equal to or greater than buf2 according to fields described in idx. + (### Currently only uses first field.) +*/ + +static int compare_recs( const QSqlRecord* buf1, const QSqlRecord* buf2, + const QSqlIndex& idx ) +{ + int cmp = 0; + + int i = 0; + const QString fn( idx.field(i)->name() ); + const QSqlField* f1 = buf1->field( fn ); + + if ( f1 ) { + switch ( f1->type() ) { // ### more types? + case QVariant::String: + case QVariant::CString: + cmp = f1->value().toString().simplifyWhiteSpace().compare( + buf2->value(fn).toString().simplifyWhiteSpace() ); + break; + default: + if ( f1->value().toDouble() < buf2->value( fn ).toDouble() ) + cmp = -1; + else if ( f1->value().toDouble() > buf2->value( fn ).toDouble() ) + cmp = 1; + } + } + + if ( idx.isDescending(i) ) + cmp = -cmp; + return cmp; +} + +#ifdef QT_DEBUG_DATAMANAGER +static void debug_datamanager_buffer( const QString& msg, QSqlRecord* cursor ) +{ + qDebug("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + qDebug( "%s", msg.latin1() ); + for ( uint j = 0; j < cursor->count(); ++j ) { + qDebug( "%s", (cursor->field(j)->name() + " type:" + + QString(cursor->field(j)->value().typeName()) + + " value:" + cursor->field(j)->value().toString()) + .latin1() ); + } +} +#endif + + +/*! \internal + + Relocates the default cursor to the record matching the cursor's +edit buffer. Only the field names specified by \a idx are used to +determine an exact match of the cursor to the edit buffer. However, +other fields in the edit buffer are also used during the search, +therefore all fields in the edit buffer should be primed with desired +values for the record being sought. This function is typically used +to relocate a cursor to the correct position after an insert or +update. For example: + +\code + QSqlCursor* myCursor = myManager.cursor(); + ... + QSqlRecord* buf = myCursor->primeUpdate(); + buf->setValue( "name", "Ola" ); + buf->setValue( "city", "Oslo" ); + ... + myCursor->update(); // update current record + myCursor->select(); // refresh the cursor + myManager.findBuffer( myCursor->primaryIndex() ); // go to the updated record +\endcode + +*/ + +//## possibly add sizeHint parameter +bool QSqlCursorManager::findBuffer( const QSqlIndex& idx, int atHint ) +{ +#ifdef QT_DEBUG_DATAMANAGER + qDebug("QSqlCursorManager::findBuffer:"); +#endif + QSqlCursor* cur = cursor(); + if ( !cur ) + return FALSE; + if ( !cur->isActive() ) + return FALSE; + if ( !idx.count() ) { + if ( cur->at() == QSql::BeforeFirst ) + cur->next(); + return FALSE; + } + QSqlRecord* buf = cur->editBuffer(); + bool indexEquals = FALSE; +#ifdef QT_DEBUG_DATAMANAGER + qDebug(" Checking hint..."); +#endif + /* check the hint */ + if ( cur->seek( atHint ) ) + indexEquals = index_matches( cur, buf, idx ); + + if ( !indexEquals ) { +#ifdef QT_DEBUG_DATAMANAGER + qDebug(" Checking current page..."); +#endif + /* check current page */ + int pageSize = 20; + int startIdx = QMAX( atHint - pageSize, 0 ); + int endIdx = atHint + pageSize; + for ( int j = startIdx; j <= endIdx; ++j ) { + if ( cur->seek( j ) ) { + indexEquals = index_matches( cur, buf, idx ); + if ( indexEquals ) + break; + } + } + } + + if ( !indexEquals && cur->driver()->hasFeature( QSqlDriver::QuerySize ) + && cur->sort().count() ) { +#ifdef QT_DEBUG_DATAMANAGER + qDebug(" Using binary search..."); +#endif + // binary search based on record buffer and current sort fields + int lo = 0; + int hi = cur->size(); + int mid; + if ( compare_recs( buf, cur, cur->sort() ) >= 0 ) + lo = cur->at(); + while ( lo != hi ) { + mid = lo + (hi - lo) / 2; + if ( !cur->seek( mid ) ) + break; + if ( index_matches( cur, buf, idx ) ) { + indexEquals = TRUE; + break; + } + int c = compare_recs( buf, cur, cur->sort() ); + if ( c < 0 ) { + hi = mid; + } else if ( c == 0 ) { + // found it, but there may be duplicates + int at = mid; + do { + mid--; + if ( !cur->seek( mid ) ) + break; + if ( index_matches( cur, buf, idx ) ) { + indexEquals = TRUE; + break; + } + } while ( compare_recs( buf, cur, cur->sort() ) == 0 ); + + if ( !indexEquals ) { + mid = at; + do { + mid++; + if ( !cur->seek( mid ) ) + break; + if ( index_matches( cur, buf, idx ) ) { + indexEquals = TRUE; + break; + } + } while ( compare_recs( buf, cur, cur->sort() ) == 0 ); + } + break; + } else if ( c > 0 ) { + lo = mid + 1; + } + } + } + + if ( !indexEquals ) { +#ifdef QT_DEBUG_DATAMANAGER + qDebug(" Using brute search..."); +#endif +#ifndef QT_NO_CURSOR + QApplication::setOverrideCursor( Qt::waitCursor ); +#endif + /* give up, use brute force */ + int startIdx = 0; + if ( cur->at() != startIdx ) { + cur->seek( startIdx ); + } + for ( ;; ) { + indexEquals = FALSE; + indexEquals = index_matches( cur, buf, idx ); + if ( indexEquals ) + break; + if ( !cur->next() ) + break; + } +#ifndef QT_NO_CURSOR + QApplication::restoreOverrideCursor(); +#endif + } +#ifdef QT_DEBUG_DATAMANAGER + qDebug(" Done, result:" + QString::number( indexEquals ) ); +#endif + return indexEquals; +} + +#ifndef QT_NO_SQL_FORM + +class QSqlFormManagerPrivate +{ +public: + QSqlFormManagerPrivate() : frm(0), rcd(0) {} + QSqlForm* frm; + QSqlRecord* rcd; +}; + + +/*! \internal + + Creates a form manager. + +*/ + +QSqlFormManager::QSqlFormManager() +{ + d = new QSqlFormManagerPrivate(); +} + +/*! \internal + + Destroys the object and frees any allocated resources. + +*/ + +QSqlFormManager::~QSqlFormManager() +{ + delete d; +} + +/*! \internal + + Clears the default form values. If there is no default form, + nothing happens, + +*/ + +void QSqlFormManager::clearValues() +{ + if ( form() ) + form()->clearValues(); +} + +/*! \internal + + Sets the form used by the form manager to \a form. If a record has + already been assigned to the form manager, that record is also used by + the \a form to display data. + + \sa form() + +*/ + +void QSqlFormManager::setForm( QSqlForm* form ) +{ + d->frm = form; + if ( d->rcd && d->frm ) + d->frm->setRecord( d->rcd ); +} + + +/*! \internal + + Returns the default form used by the form manager, or 0 if there is + none. + + \sa setForm() + +*/ + +QSqlForm* QSqlFormManager::form() +{ + return d->frm; +} + + +/*! \internal + + Sets the record used by the form manager to \a record. If a form has + already been assigned to the form manager, \a record is also used by + the default form to display data. + + \sa record() + +*/ + +void QSqlFormManager::setRecord( QSqlRecord* record ) +{ + d->rcd = record; + if ( d->frm ) { + d->frm->setRecord( d->rcd ); + } +} + + +/*! \internal + + Returns the default record used by the form manager, or 0 if there is + none. + + \sa setRecord() +*/ + +QSqlRecord* QSqlFormManager::record() +{ + return d->rcd; +} + + +/*! \internal + + Causes the default form to read its fields . If there is no + default form, nothing happens. + + \sa setForm() + +*/ + +void QSqlFormManager::readFields() +{ + if ( d->frm ) { + d->frm->readFields(); + } +} + +/*! \internal + + Causes the default form to write its fields . If there is no + default form, nothing happens. + + \sa setForm() + +*/ + +void QSqlFormManager::writeFields() +{ + if ( d->frm ) { + d->frm->writeFields(); + } +} + +#endif // QT_NO_SQL_FORM + +class QDataManagerPrivate +{ +public: + QDataManagerPrivate() + : mode( QSql::None ), autoEd( TRUE ), confEdits( 3 ), + confCancs( FALSE ) {} + QSql::Op mode; + bool autoEd; + QBitArray confEdits; + bool confCancs; + +}; + +/*! + \class QDataManager qsqlmanager_p.h + \ingroup database + + \brief The QDataManager class is an internal class for implementing + the data-aware widgets. + + \internal + + QDataManager is a strictly internal class that acts as a base class + for other data-aware widgets. + +*/ + + +/*! \internal + + Constructs an empty data handler. + +*/ + +QDataManager::QDataManager() +{ + d = new QDataManagerPrivate(); +} + + +/*! \internal + + Destroys the object and frees any allocated resources. + +*/ + +QDataManager::~QDataManager() +{ + delete d; +} + + +/*! \internal + + Virtual function which is called when an error has occurred The + default implementation displays a warning message to the user with + information about the error. + +*/ +void QDataManager::handleError( QWidget* parent, const QSqlError& e ) +{ +#ifndef QT_NO_MESSAGEBOX + if (e.driverText().isEmpty() && e.databaseText().isEmpty()) { + QMessageBox::warning ( parent, "Warning", "An error occurred while accessing the database"); + } else { + QMessageBox::warning ( parent, "Warning", e.driverText() + "\n" + e.databaseText(), + 0, 0 ); + } +#endif // QT_NO_MESSAGEBOX +} + + +/*! \internal + + Sets the internal mode to \a m. + +*/ + +void QDataManager::setMode( QSql::Op m ) +{ + d->mode = m; +} + + +/*! \internal + + Returns the current mode. + +*/ + +QSql::Op QDataManager::mode() const +{ + return d->mode; +} + + +/*! \internal + + Sets the auto-edit mode to \a auto. + +*/ + +void QDataManager::setAutoEdit( bool autoEdit ) +{ + d->autoEd = autoEdit; +} + + + +/*! \internal + + Returns TRUE if auto-edit mode is enabled; otherwise returns FALSE. + +*/ + +bool QDataManager::autoEdit() const +{ + return d->autoEd; +} + +/*! \internal + + If \a confirm is TRUE, all edit operations (inserts, updates and + deletes) will be confirmed by the user. If \a confirm is FALSE (the + default), all edits are posted to the database immediately. + +*/ +void QDataManager::setConfirmEdits( bool confirm ) +{ + d->confEdits.fill( confirm ); +} + +/*! \internal + + If \a confirm is TRUE, all inserts will be confirmed by the user. + If \a confirm is FALSE (the default), all edits are posted to the + database immediately. + +*/ + +void QDataManager::setConfirmInsert( bool confirm ) +{ + d->confEdits[ QSql::Insert ] = confirm; +} + +/*! \internal + + If \a confirm is TRUE, all updates will be confirmed by the user. + If \a confirm is FALSE (the default), all edits are posted to the + database immediately. + +*/ + +void QDataManager::setConfirmUpdate( bool confirm ) +{ + d->confEdits[ QSql::Update ] = confirm; +} + +/*! \internal + + If \a confirm is TRUE, all deletes will be confirmed by the user. + If \a confirm is FALSE (the default), all edits are posted to the + database immediately. + +*/ + +void QDataManager::setConfirmDelete( bool confirm ) +{ + d->confEdits[ QSql::Delete ] = confirm; +} + +/*! \internal + + Returns TRUE if the table confirms all edit operations (inserts, + updates and deletes), otherwise returns FALSE. +*/ + +bool QDataManager::confirmEdits() const +{ + return ( confirmInsert() && confirmUpdate() && confirmDelete() ); +} + +/*! \internal + + Returns TRUE if the table confirms inserts, otherwise returns + FALSE. +*/ + +bool QDataManager::confirmInsert() const +{ + return d->confEdits[ QSql::Insert ]; +} + +/*! \internal + + Returns TRUE if the table confirms updates, otherwise returns + FALSE. +*/ + +bool QDataManager::confirmUpdate() const +{ + return d->confEdits[ QSql::Update ]; +} + +/*! \internal + + Returns TRUE if the table confirms deletes, otherwise returns + FALSE. +*/ + +bool QDataManager::confirmDelete() const +{ + return d->confEdits[ QSql::Delete ]; +} + +/*! \internal + + If \a confirm is TRUE, all cancels will be confirmed by the user + through a message box. If \a confirm is FALSE (the default), all + cancels occur immediately. +*/ + +void QDataManager::setConfirmCancels( bool confirm ) +{ + d->confCancs = confirm; +} + +/*! \internal + + Returns TRUE if the table confirms cancels, otherwise returns FALSE. +*/ + +bool QDataManager::confirmCancels() const +{ + return d->confCancs; +} + +/*! \internal + + Virtual function which returns a confirmation for an edit of mode \a + m. Derived classes can reimplement this function and provide their + own confirmation dialog. The default implementation uses a message + box which prompts the user to confirm the edit action. The dialog + is centered over \a parent. + +*/ + +QSql::Confirm QDataManager::confirmEdit( QWidget* parent, QSql::Op m ) +{ + int ans = 2; + if ( m == QSql::Delete ) { +#ifndef QT_NO_MESSAGEBOX + ans = QMessageBox::information( parent, + qApp->translate( "QSql", "Delete" ), + qApp->translate( "QSql", "Delete this record?" ), + qApp->translate( "QSql", "Yes" ), + qApp->translate( "QSql", "No" ), + QString::null, 0, 1 ); +#else + ans = QSql::No; +#endif // QT_NO_MESSAGEBOX + } else if ( m != QSql::None ) { + QString caption; + if ( m == QSql::Insert ) { + caption = qApp->translate( "QSql", "Insert" ); + } else { // QSql::Update + caption = qApp->translate( "QSql", "Update" ); + } +#ifndef QT_NO_MESSAGEBOX + ans = QMessageBox::information( parent, caption, + qApp->translate( "QSql", "Save edits?" ), + qApp->translate( "QSql", "Yes" ), + qApp->translate( "QSql", "No" ), + qApp->translate( "QSql", "Cancel" ), + 0, 2 ); +#else + ans = QSql::No; +#endif // QT_NO_MESSAGEBOX + } + + switch ( ans ) { + case 0: + return QSql::Yes; + case 1: + return QSql::No; + default: + return QSql::Cancel; + } +} + +/*! \internal + + Virtual function which returns a confirmation for cancelling an edit + mode \a m. Derived classes can reimplement this function and + provide their own confirmation dialog. The default implementation + uses a message box which prompts the user to confirm the edit + action. The dialog is centered over \a parent. + + +*/ + +QSql::Confirm QDataManager::confirmCancel( QWidget* parent, QSql::Op ) +{ +#ifndef QT_NO_MESSAGEBOX + switch ( QMessageBox::information( parent, + qApp->translate( "QSql", "Confirm" ), + qApp->translate( "QSql", "Cancel your edits?" ), + qApp->translate( "QSql", "Yes" ), + qApp->translate( "QSql", "No" ), + QString::null, 0, 1 ) ) { + case 0: + return QSql::Yes; + case 1: + return QSql::No; + default: + return QSql::Cancel; + } +#else + return QSql::Yes; +#endif // QT_NO_MESSAGEBOX +} + +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlmanager_p.h b/main/dependencies/qt3/src/sql/qsqlmanager_p.h new file mode 100644 index 000000000..6df885867 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlmanager_p.h @@ -0,0 +1,163 @@ +/**************************************************************************** +** +** Definition of QSqlManager class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLMANAGER_P_H +#define QSQLMANAGER_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. +// +// + +#ifndef QT_H +#include "qglobal.h" +#include "qstring.h" +#include "qstringlist.h" +#include "qsql.h" +#include "qsqlerror.h" +#include "qsqlindex.h" +#include "qsqlcursor.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL + +class QSqlCursor; +class QSqlForm; +class QSqlCursorManagerPrivate; + +class QM_EXPORT_SQL QSqlCursorManager +{ +public: + QSqlCursorManager(); + virtual ~QSqlCursorManager(); + + virtual void setSort( const QSqlIndex& sort ); + virtual void setSort( const QStringList& sort ); + QStringList sort() const; + virtual void setFilter( const QString& filter ); + QString filter() const; + virtual void setCursor( QSqlCursor* cursor, bool autoDelete = FALSE ); + QSqlCursor* cursor() const; + + virtual void setAutoDelete( bool enable ); + bool autoDelete() const; + + virtual bool refresh(); + virtual bool findBuffer( const QSqlIndex& idx, int atHint = 0 ); + +private: + QSqlCursorManagerPrivate* d; +}; + +#ifndef QT_NO_SQL_FORM + +class QSqlFormManagerPrivate; + +class QM_EXPORT_SQL QSqlFormManager +{ +public: + QSqlFormManager(); + virtual ~QSqlFormManager(); + + virtual void setForm( QSqlForm* form ); + QSqlForm* form(); + virtual void setRecord( QSqlRecord* record ); + QSqlRecord* record(); + + virtual void clearValues(); + virtual void readFields(); + virtual void writeFields(); + +private: + QSqlFormManagerPrivate* d; +}; + +#endif + +class QWidget; +class QDataManagerPrivate; + +class QM_EXPORT_SQL QDataManager +{ +public: + QDataManager(); + virtual ~QDataManager(); + + virtual void setMode( QSql::Op m ); + QSql::Op mode() const; + virtual void setAutoEdit( bool autoEdit ); + bool autoEdit() const; + + virtual void handleError( QWidget* parent, const QSqlError& error ); + virtual QSql::Confirm confirmEdit( QWidget* parent, QSql::Op m ); + virtual QSql::Confirm confirmCancel( QWidget* parent, QSql::Op m ); + + virtual void setConfirmEdits( bool confirm ); + virtual void setConfirmInsert( bool confirm ); + virtual void setConfirmUpdate( bool confirm ); + virtual void setConfirmDelete( bool confirm ); + virtual void setConfirmCancels( bool confirm ); + + bool confirmEdits() const; + bool confirmInsert() const; + bool confirmUpdate() const; + bool confirmDelete() const; + bool confirmCancels() const; + +private: + QDataManagerPrivate* d; +}; + + +#endif +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlpropertymap.cpp b/main/dependencies/qt3/src/sql/qsqlpropertymap.cpp new file mode 100644 index 000000000..3c99a1c14 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlpropertymap.cpp @@ -0,0 +1,304 @@ +/**************************************************************************** +** +** Definition of QSqlPropertyMap class +** +** Created : 2000-11-20 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlpropertymap.h" + +#ifndef QT_NO_SQL_FORM + +#include "qwidget.h" +#include "qcleanuphandler.h" +#include "qmetaobject.h" +#include "qmap.h" + +class QSqlPropertyMapPrivate +{ +public: + QSqlPropertyMapPrivate() {} + QMap< QString, QString > propertyMap; +}; + +/*! + \class QSqlPropertyMap qsqlpropertymap.h + \brief The QSqlPropertyMap class is used to map widgets to SQL fields. + + \ingroup database + \module sql + + The SQL module uses Qt \link properties.html object + properties\endlink to insert and extract values from editor + widgets. + + This class is used to map editors to SQL fields. This works by + associating SQL editor class names to the properties used to + insert and extract values to/from the editor. + + For example, a QLineEdit can be used to edit text strings and + other data types in QDataTables or QSqlForms. Several properties + are defined in QLineEdit, but only the \e text property is used to + insert and extract text from a QLineEdit. Both QDataTable and + QSqlForm use the global QSqlPropertyMap for inserting and + extracting values to and from an editor widget. The global + property map defines several common widgets and properties that + are suitable for many applications. You can add and remove widget + properties to suit your specific needs. + + If you want to use custom editors with your QDataTable or + QSqlForm, you must install your own QSqlPropertyMap for that table + or form. Example: + + \code + QSqlPropertyMap *myMap = new QSqlPropertyMap(); + QSqlForm *myForm = new QSqlForm( this ); + MyEditor myEditor( this ); + + // Set the QSqlForm's record buffer to the update buffer of + // a pre-existing QSqlCursor called 'cur'. + myForm->setRecord( cur->primeUpdate() ); + + // Install the customized map + myMap->insert( "MyEditor", "content" ); + myForm->installPropertyMap( myMap ); // myForm now owns myMap + ... + // Insert a field into the form that uses a myEditor to edit the + // field 'somefield' + myForm->insert( &myEditor, "somefield" ); + + // Update myEditor with the value from the mapped database field + myForm->readFields(); + ... + // Let the user edit the form + ... + // Update the database fields with the values in the form + myForm->writeFields(); + ... + \endcode + + You can also replace the global QSqlPropertyMap that is used by + default. (Bear in mind that QSqlPropertyMap takes ownership of the + new default map.) + + \code + QSqlPropertyMap *myMap = new QSqlPropertyMap; + + myMap->insert( "MyEditor", "content" ); + QSqlPropertyMap::installDefaultMap( myMap ); + ... + \endcode + + \sa QDataTable, QSqlForm, QSqlEditorFactory +*/ + +/*! + +Constructs a QSqlPropertyMap. + +The default property mappings used by Qt widgets are: +\table +\header \i Widgets \i Property +\row \i \l QCheckBox, + \l QRadioButton + \i checked +\row \i \l QComboBox, + \l QListBox + \i currentItem +\row \i \l QDateEdit + \i date +\row \i \l QDateTimeEdit + \i dateTime +\row \i \l QTextBrowser + \i source +\row \i \l QButton, + \l QDial, + \l QLabel, + \l QLineEdit, + \l QMultiLineEdit, + \l QPushButton, + \l QTextEdit, + \i text +\row \i \l QTimeEdit + \i time +\row \i \l QLCDNumber, + \l QScrollBar + \l QSlider, + \l QSpinBox + \i value +\endtable +*/ + +QSqlPropertyMap::QSqlPropertyMap() +{ + d = new QSqlPropertyMapPrivate(); + const struct MapData { + const char *classname; + const char *property; + } mapData[] = { + { "QButton", "text" }, + { "QCheckBox", "checked" }, + { "QRadioButton", "checked" }, + { "QComboBox", "currentItem" }, + { "QDateEdit", "date" }, + { "QDateTimeEdit", "dateTime" }, + { "QDial", "value" }, + { "QLabel", "text" }, + { "QLCDNumber", "value" }, + { "QLineEdit", "text" }, + { "QListBox", "currentItem" }, + { "QMultiLineEdit", "text" }, + { "QPushButton", "text" }, + { "QScrollBar", "value" }, + { "QSlider", "value" }, + { "QSpinBox", "value" }, + { "QTextBrowser", "source" }, + { "QTextEdit", "text" }, + { "QTextView", "text" }, + { "QTimeEdit", "time" } + }; + + const MapData *m = mapData; + for ( uint i = 0; i < sizeof(mapData)/sizeof(MapData); i++, m++ ) + d->propertyMap.insert( m->classname, m->property ); +} + +/*! + Destroys the QSqlPropertyMap. + + Note that if the QSqlPropertyMap is installed with + installPropertyMap() the object it was installed into, e.g. the + QSqlForm, takes ownership and will delete the QSqlPropertyMap when + necessary. +*/ +QSqlPropertyMap::~QSqlPropertyMap() +{ + delete d; +} + +/*! + Returns the mapped property of \a widget as a QVariant. +*/ +QVariant QSqlPropertyMap::property( QWidget * widget ) +{ + if( !widget ) return QVariant(); + const QMetaObject* mo = widget->metaObject(); + while ( mo && !d->propertyMap.contains( QString( mo->className() ) ) ) + mo = mo->superClass(); + + if ( !mo ) { +#ifdef QT_CHECK_RANGE + qWarning("QSqlPropertyMap::property: %s does not exist", widget->metaObject()->className() ); +#endif + return QVariant(); + } + return widget->property( d->propertyMap[ mo->className() ] ); +} + +/*! + Sets the property of \a widget to \a value. +*/ +void QSqlPropertyMap::setProperty( QWidget * widget, const QVariant & value ) +{ + if( !widget ) return; + + QMetaObject* mo = widget->metaObject(); + while ( mo && !d->propertyMap.contains( QString( mo->className() ) ) ) + mo = mo->superClass(); + if ( !mo ) { +#ifdef QT_CHECK_RANGE + qWarning("QSqlPropertyMap::setProperty: %s not handled by QSqlPropertyMap", widget->metaObject()->className() ); +#endif + return; + } + + widget->setProperty( d->propertyMap[ mo->className() ], value ); +} + +/*! + Insert a new classname/property pair, which is used for custom SQL + field editors. There \e must be a \c Q_PROPERTY clause in the \a + classname class declaration for the \a property. +*/ +void QSqlPropertyMap::insert( const QString & classname, + const QString & property ) +{ + d->propertyMap[ classname ] = property; +} + +/*! + Removes \a classname from the map. +*/ +void QSqlPropertyMap::remove( const QString & classname ) +{ + d->propertyMap.remove( classname ); +} + +static QSqlPropertyMap * defaultmap = 0; +static QCleanupHandler< QSqlPropertyMap > qsql_cleanup_property_map; + +/*! + Returns the application global QSqlPropertyMap. +*/ +QSqlPropertyMap * QSqlPropertyMap::defaultMap() +{ + if( defaultmap == 0 ){ + defaultmap = new QSqlPropertyMap(); + qsql_cleanup_property_map.add( &defaultmap ); + } + return defaultmap; +} + +/*! + Replaces the global default property map with \a map. All + QDataTable and QSqlForm instantiations will use this new map for + inserting and extracting values to and from editors. + \e{QSqlPropertyMap takes ownership of \a map, and destroys it + when it is no longer needed.} +*/ +void QSqlPropertyMap::installDefaultMap( QSqlPropertyMap * map ) +{ + if( map == 0 ) return; + + if( defaultmap != 0 ){ + qsql_cleanup_property_map.remove( &defaultmap ); + delete defaultmap; + } + defaultmap = map; + qsql_cleanup_property_map.add( &defaultmap ); +} + +#endif // QT_NO_SQL_FORM diff --git a/main/dependencies/qt3/src/sql/qsqlpropertymap.h b/main/dependencies/qt3/src/sql/qsqlpropertymap.h new file mode 100644 index 000000000..46d14adef --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlpropertymap.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Definition of QSqlPropertyMap class +** +** Created : 2000-11-20 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLPROPERTYMAP_H +#define QSQLPROPERTYMAP_H + +#ifndef QT_H +#include "qvariant.h" +#include "qstring.h" +#endif // QT_H + +#ifndef QT_NO_SQL_FORM + +class QWidget; +class QSqlPropertyMapPrivate; + +class Q_EXPORT QSqlPropertyMap { +public: + QSqlPropertyMap(); + virtual ~QSqlPropertyMap(); + + QVariant property( QWidget * widget ); + virtual void setProperty( QWidget * widget, const QVariant & value ); + + void insert( const QString & classname, const QString & property ); + void remove( const QString & classname ); + + static QSqlPropertyMap * defaultMap(); + static void installDefaultMap( QSqlPropertyMap * map ); + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QSqlPropertyMap( const QSqlPropertyMap & ); + QSqlPropertyMap &operator=( const QSqlPropertyMap & ); +#endif + QSqlPropertyMapPrivate* d; + +}; + +#endif // QT_NO_SQL_FORM +#endif // QSQLPROPERTYMAP_H diff --git a/main/dependencies/qt3/src/sql/qsqlquery.cpp b/main/dependencies/qt3/src/sql/qsqlquery.cpp new file mode 100644 index 000000000..fec234395 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlquery.cpp @@ -0,0 +1,1215 @@ +/**************************************************************************** +** +** Implementation of QSqlQuery class +** +** Created : 2000-11-03 +** +** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlquery.h" + +#ifndef QT_NO_SQL + +//#define QT_DEBUG_SQL + +#include "qsqlresult.h" +#include "qsqldriver.h" +#include "qsqldatabase.h" +#include "qsql.h" +#include "qregexp.h" +#include "private/qsqlextension_p.h" + + +/*! +\internal +*/ +QSqlResultShared::QSqlResultShared( QSqlResult* result ): sqlResult(result) +{ + if ( result ) + connect( result->driver(), SIGNAL(destroyed()), this, SLOT(slotResultDestroyed()) ); +} + +/*! +\internal +*/ +QSqlResultShared::~QSqlResultShared() +{ + delete sqlResult; +} + +/*! +\internal + +In case a plugin gets unloaded the pointer to the sqlResult gets invalid +*/ +void QSqlResultShared::slotResultDestroyed() +{ + delete sqlResult; + sqlResult = 0; +} + +/*! + \class QSqlQuery qsqlquery.h + \brief The QSqlQuery class provides a means of executing and + manipulating SQL statements. + + \ingroup database + \mainclass + \module sql + + 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, e.g. \c SELECT, \c INSERT, \c + UPDATE and \c DELETE, and also DDL (data definition language) + statements, e.g. \c{CREATE 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 (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. + + Navigating records is performed with the following functions: + + \list + \i \c next() + \i \c prev() + \i \c first() + \i \c last() + \i \c \link QSqlQuery::seek() seek\endlink(int) + \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. using next() or + using seek() with a positive offset, you can use setForwardOnly() + and save a significant amount of memory overhead. 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: + + \code + QSqlQuery query( "SELECT name FROM customer" ); + while ( query.next() ) { + QString name = query.value(0).toString(); + doSomething( name ); + } + \endcode + + To access the data returned by a query, use the value() method. + Each field in the data returned by a SELECT statement is accessed + by passing the field's position in the statement, starting from 0. + Information about the fields can be obtained via QSqlDatabase::record(). + For the sake of efficiency there are no functions to access a field + by name. (The \l QSqlCursor class provides a higher-level interface + with field access by name and automatic SQL generation.) + + QSqlQuery supports prepared query execution and the binding of + parameter values to placeholders. Some databases don't support + these features, so for them 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. The exception is positional binding using named + placeholders, which requires that the database supports prepared + queries. + + Oracle databases identify placeholders by using a colon-name + syntax, e.g \c{:name}. ODBC simply uses \c ? characters. Qt + supports both syntaxes (although you can't mix them in the same + query). + + Below we present the same example using each of the four different + binding approaches. + + <b>Named binding using named placeholders</b> + \code + QSqlQuery query; + query.prepare( "INSERT INTO atable (id, forename, surname) " + "VALUES (:id, :forename, :surname)" ); + query.bindValue( ":id", 1001 ); + query.bindValue( ":forename", "Bart" ); + query.bindValue( ":surname", "Simpson" ); + query.exec(); + \endcode + + <b>Positional binding using named placeholders</b> + \code + QSqlQuery query; + query.prepare( "INSERT INTO atable (id, forename, surname) " + "VALUES (:id, :forename, :surname)" ); + query.bindValue( 0, 1001 ); + query.bindValue( 1, "Bart" ); + query.bindValue( 2, "Simpson" ); + query.exec(); + \endcode + <b>Note:</b> Using positional binding with named placeholders will + only work if the database supports prepared queries. This can be + checked with QSqlDriver::hasFeature() using QSqlDriver::PreparedQueries + as argument for driver feature. + + <b>Binding values using positional placeholders #1</b> + \code + QSqlQuery query; + query.prepare( "INSERT INTO atable (id, forename, surname) " + "VALUES (?, ?, ?)" ); + query.bindValue( 0, 1001 ); + query.bindValue( 1, "Bart" ); + query.bindValue( 2, "Simpson" ); + query.exec(); + \endcode + + <b>Binding values using positional placeholders #2</b> + \code + query.prepare( "INSERT INTO atable (id, forename, surname) " + "VALUES (?, ?, ?)" ); + query.addBindValue( 1001 ); + query.addBindValue( "Bart" ); + query.addBindValue( "Simpson" ); + query.exec(); + \endcode + + <b>Binding values to a stored procedure</b> + 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. + \code + QSqlQuery query; + query.prepare( "call AsciiToInt(?, ?)" ); + query.bindValue( 0, "A" ); + query.bindValue( 1, 0, QSql::Out ); + query.exec(); + int i = query.boundValue( 1 ).toInt(); // i is 65. + \endcode + + \sa QSqlDatabase QSqlCursor QVariant +*/ + +/*! + Creates a QSqlQuery object which uses the QSqlResult \a r to + communicate with a database. +*/ + +QSqlQuery::QSqlQuery( QSqlResult * r ) +{ + d = new QSqlResultShared( r ); +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QSqlQuery::~QSqlQuery() +{ + if (d->deref()) { + delete d; + } +} + +/*! + Constructs a copy of \a other. +*/ + +QSqlQuery::QSqlQuery( const QSqlQuery& other ) + : d(other.d) +{ + d->ref(); +} + +/*! + Creates a QSqlQuery object using the SQL \a query and the database + \a db. If \a db is 0, (the default), the application's default + database is used. If \a query is not a null string, it will be + executed. + + \sa QSqlDatabase +*/ +QSqlQuery::QSqlQuery( const QString& query, QSqlDatabase* db ) +{ + init( query, db ); +} + +/*! + Creates a QSqlQuery object using the database \a db. If \a db is + 0, the application's default database is used. + + \sa QSqlDatabase +*/ + +QSqlQuery::QSqlQuery( QSqlDatabase* db ) +{ + init( QString::null, db ); +} + +/*! \internal +*/ + +void QSqlQuery::init( const QString& query, QSqlDatabase* db ) +{ + d = new QSqlResultShared( 0 ); + QSqlDatabase* database = db; + if ( !database ) + database = QSqlDatabase::database( QSqlDatabase::defaultConnection, FALSE ); + if ( database ) + *this = database->driver()->createQuery(); + if ( !query.isNull() ) + exec( query ); +} + +/*! + Assigns \a other to the query. +*/ + +QSqlQuery& QSqlQuery::operator=( const QSqlQuery& other ) +{ + other.d->ref(); + deref(); + d = other.d; + return *this; +} + +/*! + Returns TRUE if the query is 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 ) + return FALSE; + if ( d->sqlResult->isActive() && d->sqlResult->isValid() ) + return d->sqlResult->isNull( field ); + return FALSE; +} + +/*! + Executes the SQL in \a query. Returns TRUE and sets the query + state to active if the query was successful; otherwise returns + FALSE and sets the query state to inactive. 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, e.g. using next(). + + Note that the last error for this query is reset when exec() is + called. + + \sa isActive() isValid() next() prev() first() last() seek() +*/ + +bool QSqlQuery::exec ( const QString& query ) +{ + if ( !d->sqlResult ) + return FALSE; + if ( d->sqlResult->extension() && driver()->hasFeature( QSqlDriver::PreparedQueries ) ) + d->sqlResult->extension()->clear(); + d->sqlResult->setActive( FALSE ); + d->sqlResult->setLastError( QSqlError() ); + d->sqlResult->setAt( QSql::BeforeFirst ); + if ( !driver() ) { +#ifdef QT_CHECK_RANGE + qWarning("QSqlQuery::exec: no driver" ); +#endif + return FALSE; + } + if ( d->count > 1 ) + *this = driver()->createQuery(); + d->sqlResult->setQuery( query.stripWhiteSpace() ); + d->executedQuery = d->sqlResult->lastQuery(); + if ( !driver()->isOpen() || driver()->isOpenError() ) { +#ifdef QT_CHECK_RANGE + qWarning("QSqlQuery::exec: database not open" ); +#endif + return FALSE; + } + if ( query.isNull() || query.length() == 0 ) { +#ifdef QT_CHECK_RANGE + qWarning("QSqlQuery::exec: empty query" ); +#endif + return FALSE; + } +#ifdef QT_DEBUG_SQL + qDebug( "\n QSqlQuery: " + query ); +#endif + return d->sqlResult->reset( query ); +} + +/*! + Returns the value of the \a{i}-th field in the query (zero based). + + The fields are numbered from left to right using the text of the + \c SELECT statement, e.g. in \c{SELECT forename, surname FROM people}, + 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 i does not exist, if + the query is inactive, or if the query is positioned on an invalid + record. + + \sa prev() next() first() last() seek() isActive() isValid() +*/ + +QVariant QSqlQuery::value( int i ) const +{ + if ( !d->sqlResult ) + return QVariant(); + if ( isActive() && isValid() && ( i > QSql::BeforeFirst ) ) { + return d->sqlResult->data( i ); + } else { +#ifdef QT_CHECK_RANGE + qWarning( "QSqlQuery::value: not positioned on a valid record" ); +#endif + } + return QVariant(); +} + +/*! + Returns the current internal position of the query. The first + record is at position zero. If the position is invalid, a + QSql::Location will be returned indicating the invalid position. + + \sa prev() next() first() last() seek() isActive() isValid() +*/ + +int QSqlQuery::at() const +{ + if ( !d->sqlResult ) + return QSql::BeforeFirst; + return d->sqlResult->at(); +} + +/*! + Returns the text of the current query being used, or QString::null + if there is no current query text. + + \sa executedQuery() +*/ + +QString QSqlQuery::lastQuery() const +{ + if ( !d->sqlResult ) + return QString::null; + return d->sqlResult->lastQuery(); +} + +/*! + Returns the database driver associated with the query. +*/ + +const QSqlDriver* QSqlQuery::driver() const +{ + if ( !d->sqlResult ) + return 0; + return d->sqlResult->driver(); +} + +/*! + Returns the result associated with the query. +*/ + +const QSqlResult* QSqlQuery::result() const +{ + return d->sqlResult; +} + +/*! + Retrieves the record at position (offset) \a i, 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 active state and + isSelect() must return TRUE before calling this function. + + If \a relative is FALSE (the default), the following rules apply: + + \list + \i If \a i is negative, the result is positioned before the + first record and FALSE is returned. + \i Otherwise, an attempt is made to move to the record at position + \a i. If the record at position \a i 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 + \i If the result is currently positioned before the first + record or on the first record, and \a i is negative, there is no + change, and FALSE is returned. + \i If the result is currently located after the last record, and + \a i is positive, there is no change, and FALSE is returned. + \i If the result is currently located somewhere in the middle, + and the relative offset \a i moves the result below zero, the + result is positioned before the first record and FALSE is + returned. + \i Otherwise, an attempt is made to move to the record \a i + records ahead of the current record (or \a i records behind the + current record if \a i is negative). If the record at offset \a i + could not be retrieved, the result is positioned after the last + record if \a i >= 0, (or before the first record if \a i is + negative), and FALSE is returned. If the record is successfully + retrieved, TRUE is returned. + \endlist + + \sa next() prev() first() last() at() isActive() isValid() +*/ +bool QSqlQuery::seek( int i, bool relative ) +{ + if ( !isSelect() || !isActive() ) + return FALSE; + beforeSeek(); + checkDetach(); + int actualIdx; + if ( !relative ) { // arbitrary seek + if ( i < 0 ) { + d->sqlResult->setAt( QSql::BeforeFirst ); + afterSeek(); + return FALSE; + } + actualIdx = i; + } else { + switch ( at() ) { // relative seek + case QSql::BeforeFirst: + if ( i > 0 ) + actualIdx = i; + else { + afterSeek(); + return FALSE; + } + break; + case QSql::AfterLast: + if ( i < 0 ) { + d->sqlResult->fetchLast(); + actualIdx = at() + i; + } else { + afterSeek(); + return FALSE; + } + break; + default: + if ( ( at() + i ) < 0 ) { + d->sqlResult->setAt( QSql::BeforeFirst ); + afterSeek(); + return FALSE; + } + actualIdx = at() + i; + break; + } + } + // let drivers optimize + if ( isForwardOnly() && actualIdx < at() ) { +#ifdef QT_CHECK_RANGE + qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query" ); +#endif + afterSeek(); + return FALSE; + } + if ( actualIdx == ( at() + 1 ) && at() != QSql::BeforeFirst ) { + if ( !d->sqlResult->fetchNext() ) { + d->sqlResult->setAt( QSql::AfterLast ); + afterSeek(); + return FALSE; + } + afterSeek(); + return TRUE; + } + if ( actualIdx == ( at() - 1 ) ) { + if ( !d->sqlResult->fetchPrev() ) { + d->sqlResult->setAt( QSql::BeforeFirst ); + afterSeek(); + return FALSE; + } + afterSeek(); + return TRUE; + } + if ( !d->sqlResult->fetch( actualIdx ) ) { + d->sqlResult->setAt( QSql::AfterLast ); + afterSeek(); + return FALSE; + } + afterSeek(); + 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 an active state and isSelect() must return TRUE before + calling this function or it will do nothing and return FALSE. + + The following rules apply: + + \list + \i 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. + + \i If the result is currently located after the last record, + there is no change and FALSE is returned. + + \i 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 prev() first() last() seek() at() isActive() isValid() +*/ + +bool QSqlQuery::next() +{ + if ( !isSelect() || !isActive() ) + return FALSE; + beforeSeek(); + checkDetach(); + bool b = FALSE; + switch ( at() ) { + case QSql::BeforeFirst: + b = d->sqlResult->fetchFirst(); + afterSeek(); + return b; + case QSql::AfterLast: + afterSeek(); + return FALSE; + default: + if ( !d->sqlResult->fetchNext() ) { + d->sqlResult->setAt( QSql::AfterLast ); + afterSeek(); + return FALSE; + } + afterSeek(); + 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 an active state and isSelect() must return TRUE before + calling this function or it will do nothing and return FALSE. + + The following rules apply: + + \list + \i If the result is currently located before the first record, + there is no change and FALSE is returned. + + \i If the result is currently located after the last record, an + attempt is made to retrieve the last record. + + \i 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::prev() +{ + if ( !isSelect() || !isActive() ) + return FALSE; + if ( isForwardOnly() ) { +#ifdef QT_CHECK_RANGE + qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query" ); +#endif + return FALSE; + } + + beforeSeek(); + checkDetach(); + bool b = FALSE; + switch ( at() ) { + case QSql::BeforeFirst: + afterSeek(); + return FALSE; + case QSql::AfterLast: + b = d->sqlResult->fetchLast(); + afterSeek(); + return b; + default: + if ( !d->sqlResult->fetchPrev() ) { + d->sqlResult->setAt( QSql::BeforeFirst ); + afterSeek(); + return FALSE; + } + afterSeek(); + 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 an 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() prev() last() seek() at() isActive() isValid() +*/ + +bool QSqlQuery::first() +{ + if ( !isSelect() || !isActive() ) + return FALSE; + if ( isForwardOnly() && at() > QSql::BeforeFirst ) { +#ifdef QT_CHECK_RANGE + qWarning("QSqlQuery::seek: cannot seek backwards in a forward only query" ); +#endif + return FALSE; + } + beforeSeek(); + checkDetach(); + bool b = FALSE; + b = d->sqlResult->fetchFirst(); + afterSeek(); + 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 an 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() prev() first() seek() at() isActive() isValid() +*/ + +bool QSqlQuery::last() +{ + if ( !isSelect() || !isActive() ) + return FALSE; + beforeSeek(); + checkDetach(); + bool b = FALSE; + b = d->sqlResult->fetchLast(); + afterSeek(); + 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-SELECT + statement, use numRowsAffected(). + + \sa isActive() numRowsAffected() QSqlDriver::hasFeature() +*/ +int QSqlQuery::size() const +{ + if ( !d->sqlResult ) + return -1; + 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; see size() instead. If the + query is not active (isActive() returns FALSE), -1 is returned. + + \sa size() QSqlDriver::hasFeature() +*/ + +int QSqlQuery::numRowsAffected() const +{ + if ( !d->sqlResult ) + return -1; + if ( isActive() ) + return d->sqlResult->numRowsAffected(); + return -1; +} + +/*! + Returns error information about the last error (if any) that + occurred. + + \sa QSqlError +*/ + +QSqlError QSqlQuery::lastError() const +{ + if ( !d->sqlResult ) + return QSqlError(); + return d->sqlResult->lastError(); +} + +/*! + Returns TRUE if the query is currently positioned on a valid + record; otherwise returns FALSE. +*/ + +bool QSqlQuery::isValid() const +{ + if ( !d->sqlResult ) + return FALSE; + return d->sqlResult->isValid(); +} + +/*! + Returns TRUE if the query is currently active; otherwise returns + FALSE. +*/ + +bool QSqlQuery::isActive() const +{ + if ( !d->sqlResult ) + return FALSE; + return d->sqlResult->isActive(); +} + +/*! + Returns TRUE if the current query is a \c SELECT statement; + otherwise returns FALSE. +*/ + +bool QSqlQuery::isSelect() const +{ + if ( !d->sqlResult ) + return FALSE; + return d->sqlResult->isSelect(); +} + +/*! + Returns TRUE if you can only scroll \e forward through a result + set; otherwise returns FALSE. + + \sa setForwardOnly() +*/ +bool QSqlQuery::isForwardOnly() const +{ + if ( !d->sqlResult ) + return FALSE; + return d->sqlResult->isForwardOnly(); +} + +/*! + Sets forward only mode to \a forward. If forward is TRUE only + next(), and seek() with positive values, are allowed for + navigating the results. Forward only mode needs far less memory + since results do not need to be cached. + + Forward only mode is off by default. + + Forward only mode cannot be used with data aware widgets like + QDataTable, since they must to be able to scroll backward as well + as forward. + + \sa isForwardOnly(), next(), seek() +*/ +void QSqlQuery::setForwardOnly( bool forward ) +{ + if ( d->sqlResult ) + d->sqlResult->setForwardOnly( forward ); +} + +/*! + \internal +*/ + +void QSqlQuery::deref() +{ + if ( d->deref() ) { + delete d; + d = 0; + } +} + +/*! + \internal +*/ + +bool QSqlQuery::checkDetach() +{ + if ( d->count > 1 && d->sqlResult ) { + QString sql = d->sqlResult->lastQuery(); + *this = driver()->createQuery(); + exec( sql ); + return TRUE; + } + return FALSE; +} + + +/*! + Protected virtual function called before the internal record + pointer is moved to a new record. The default implementation does + nothing. +*/ + +void QSqlQuery::beforeSeek() +{ + +} + + +/*! + Protected virtual function called after the internal record + pointer is moved to a new record. The default implementation does + nothing. +*/ + +void QSqlQuery::afterSeek() +{ + +} + +// XXX: Hack to keep BCI - remove in 4.0. QSqlExtension should be +// removed, and the prepare(), exec() etc. fu's should be +// made virtual members of QSqlQuery/QSqlResult + +/*! + Prepares the SQL query \a query for execution. The query may + contain placeholders for binding values. Both Oracle style + colon-name (e.g. \c{:surname}), and ODBC style (e.g. \c{?}) + placeholders are supported; but they cannot be mixed in the same + query. See the \link #details Description\endlink for examples. + + \sa exec(), bindValue(), addBindValue() +*/ +bool QSqlQuery::prepare( const QString& query ) +{ + if ( !d->sqlResult || !d->sqlResult->extension() ) + return FALSE; + d->sqlResult->setActive( FALSE ); + d->sqlResult->setLastError( QSqlError() ); + d->sqlResult->setAt( QSql::BeforeFirst ); + d->sqlResult->extension()->clear(); + if ( !driver() ) { +#ifdef QT_CHECK_RANGE + qWarning("QSqlQuery::prepare: no driver" ); +#endif + return FALSE; + } + if ( d->count > 1 ) + *this = driver()->createQuery(); + d->sqlResult->setQuery( query.stripWhiteSpace() ); + if ( !driver()->isOpen() || driver()->isOpenError() ) { +#ifdef QT_CHECK_RANGE + qWarning("QSqlQuery::prepare: database not open" ); +#endif + return FALSE; + } + if ( query.isNull() || query.length() == 0 ) { +#ifdef QT_CHECK_RANGE + qWarning("QSqlQuery::prepare: empty query" ); +#endif + return FALSE; + } +#ifdef QT_DEBUG_SQL + qDebug( "\n QSqlQuery: " + query ); +#endif + QString q = query; + QRegExp rx(QString::fromLatin1("'[^']*'|:([a-zA-Z0-9_]+)")); + if ( driver()->hasFeature( QSqlDriver::PreparedQueries ) ) { + // below we substitute Oracle placeholders with ODBC ones and + // vice versa to make this db independent + int i = 0, cnt = 0; + if ( driver()->hasFeature( QSqlDriver::NamedPlaceholders ) ) { + QRegExp rx(QString::fromLatin1("'[^']*'|\\?")); + while ( (i = rx.search( q, i )) != -1 ) { + if ( rx.cap(0) == "?" ) { + q = q.replace( i, 1, ":f" + QString::number(cnt) ); + cnt++; + } + i += rx.matchedLength(); + } + } else if ( driver()->hasFeature( QSqlDriver::PositionalPlaceholders ) ) { + while ( (i = rx.search( q, i )) != -1 ) { + if ( rx.cap(1).isEmpty() ) { + i += rx.matchedLength(); + } else { + // record the index of the placeholder - needed + // for emulating named bindings with ODBC + d->sqlResult->extension()->index[ cnt ]= rx.cap(0); + q = q.replace( i, rx.matchedLength(), "?" ); + i++; + cnt++; + } + } + } + d->executedQuery = q; + return d->sqlResult->extension()->prepare( q ); + } else { + int i = 0; + while ( (i = rx.search( q, i )) != -1 ) { + if ( !rx.cap(1).isEmpty() ) + d->sqlResult->extension()->holders.append( Holder( rx.cap(0), i ) ); + i += rx.matchedLength(); + } + return TRUE; // fake prepares should always succeed + } +} + +/*! + \overload + + Executes a previously prepared SQL query. Returns TRUE if the + query executed successfully; otherwise returns FALSE. + + \sa prepare(), bindValue(), addBindValue() +*/ +bool QSqlQuery::exec() +{ + bool ret; + if ( !d->sqlResult || !d->sqlResult->extension() ) + return FALSE; + if ( driver()->hasFeature( QSqlDriver::PreparedQueries ) ) { + ret = d->sqlResult->extension()->exec(); + } else { + // fake preparation - just replace the placeholders.. + QString query = d->sqlResult->lastQuery(); + if ( d->sqlResult->extension()->bindMethod() == QSqlExtension::BindByName ) { + int i; + QVariant val; + QString holder; + for ( i = (int)d->sqlResult->extension()->holders.count() - 1; i >= 0; --i ) { + holder = d->sqlResult->extension()->holders[ (uint)i ].holderName; + val = d->sqlResult->extension()->values[ holder ].value; + QSqlField f( "", val.type() ); + if ( val.isNull() ) + f.setNull(); + else + f.setValue( val ); + query = query.replace( (uint)d->sqlResult->extension()->holders[ (uint)i ].holderPos, + holder.length(), driver()->formatValue( &f ) ); + } + } else { + QMap<int, QString>::ConstIterator it; + QString val; + int i = 0; + for ( it = d->sqlResult->extension()->index.begin(); + it != d->sqlResult->extension()->index.end(); ++it ) { + i = query.find( '?', i ); + if ( i > -1 ) { + QSqlField f( "", d->sqlResult->extension()->values[ it.data() ].value.type() ); + if ( d->sqlResult->extension()->values[ it.data() ].value.isNull() ) + f.setNull(); + else + f.setValue( d->sqlResult->extension()->values[ it.data() ].value ); + val = driver()->formatValue( &f ); + query = query.replace( i, 1, driver()->formatValue( &f ) ); + i += val.length(); + } + } + } + // have to retain the original query w/placeholders.. + QString orig = d->sqlResult->lastQuery(); + ret = exec( query ); + d->executedQuery = query; + d->sqlResult->setQuery( orig ); + } + d->sqlResult->extension()->resetBindCount(); + return ret; +} + +/*! + 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 type + is \c QSql::Out or \c QSql::InOut, the placeholder will be + overwritten with data from the database after the exec() call. + + \sa addBindValue(), prepare(), exec() +*/ +void QSqlQuery::bindValue( const QString& placeholder, const QVariant& val, QSql::ParameterType type ) +{ + if ( !d->sqlResult || !d->sqlResult->extension() ) + return; + d->sqlResult->extension()->bindValue( placeholder, val, type ); +} + +/*! + \overload + + 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 type + is \c QSql::Out or \c QSql::InOut, the placeholder will be + overwritten with data from the database after the exec() call. + + \sa addBindValue(), prepare(), exec() +*/ +void QSqlQuery::bindValue( int pos, const QVariant& val, QSql::ParameterType type ) +{ + if ( !d->sqlResult || !d->sqlResult->extension() ) + return; + d->sqlResult->extension()->bindValue( pos, val, type ); +} + +/*! + 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 type is \c QSql::Out or \c QSql::InOut, the placeholder will + be overwritten with data from the database after the exec() call. + + \sa bindValue(), prepare(), exec() +*/ +void QSqlQuery::addBindValue( const QVariant& val, QSql::ParameterType type ) +{ + if ( !d->sqlResult || !d->sqlResult->extension() ) + return; + d->sqlResult->extension()->addBindValue( val, type ); +} + + +/*! + \overload + + Binds the placeholder with type \c QSql::In. +*/ +void QSqlQuery::bindValue( const QString& placeholder, const QVariant& val ) +{ + bindValue( placeholder, val, QSql::In ); +} + +/*! + \overload + + Binds the placeholder at position \a pos with type \c QSql::In. +*/ +void QSqlQuery::bindValue( int pos, const QVariant& val ) +{ + bindValue( pos, val, QSql::In ); +} + +/*! + \overload + + Binds the placeholder with type \c QSql::In. +*/ +void QSqlQuery::addBindValue( const QVariant& val ) +{ + addBindValue( val, QSql::In ); +} + +/*! + Returns the value for the \a placeholder. +*/ +QVariant QSqlQuery::boundValue( const QString& placeholder ) const +{ + if ( !d->sqlResult || !d->sqlResult->extension() ) + return QVariant(); + return d->sqlResult->extension()->boundValue( placeholder ); +} + +/*! + \overload + + Returns the value for the placeholder at position \a pos. +*/ +QVariant QSqlQuery::boundValue( int pos ) const +{ + if ( !d->sqlResult || !d->sqlResult->extension() ) + return QVariant(); + return d->sqlResult->extension()->boundValue( pos ); +} + +/*! + Returns a map of the bound values. + + The bound values can be examined in the following way: + \code + QSqlQuery query; + ... + // Examine the bound values - bound using named binding + QMap<QString, QVariant>::ConstIterator it; + QMap<QString, QVariant> vals = query.boundValues(); + for ( it = vals.begin(); it != vals.end(); ++it ) + qWarning( "Placeholder: " + it.key() + ", Value: " + (*it).toString() ); + ... + + // Examine the bound values - bound using positional binding + QValueList<QVariant>::ConstIterator it; + QValueList<QVariant> list = query.boundValues().values(); + int i = 0; + for ( it = list.begin(); it != list.end(); ++it ) + qWarning( "Placeholder pos: %d, Value: " + (*it).toString(), i++ ); + ... + + \endcode +*/ +QMap<QString,QVariant> QSqlQuery::boundValues() const +{ + if ( !d->sqlResult || !d->sqlResult->extension() ) + return QMap<QString,QVariant>(); + return d->sqlResult->extension()->boundValues(); +} + +/*! + Returns the last query that was executed. + + In most cases this function returns the same 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. Useful for debugging purposes. + + \sa lastQuery() +*/ +QString QSqlQuery::executedQuery() const +{ + return d->executedQuery; +} +#endif // QT_NO_SQL diff --git a/main/dependencies/qt3/src/sql/qsqlquery.h b/main/dependencies/qt3/src/sql/qsqlquery.h new file mode 100644 index 000000000..cf176d849 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlquery.h @@ -0,0 +1,133 @@ +/**************************************************************************** +** +** Definition of QSqlQuery class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLQUERY_H +#define QSQLQUERY_H + +#ifndef QT_H +#include "qobject.h" +#include "qstring.h" +#include "qvariant.h" +#include "qvaluelist.h" +#include "qsqlerror.h" +#include "qsqlfield.h" +#include "qsql.h" +#endif // QT_H + +#ifndef QT_NO_SQL + +class QSqlDriver; +class QSqlResult; +class QSqlDatabase; + +class Q_EXPORT QSqlResultShared : public QObject, public QShared +{ + Q_OBJECT +public: + QSqlResultShared( QSqlResult* result ); + virtual ~QSqlResultShared(); + QSqlResult* sqlResult; + QString executedQuery; +private slots: + void slotResultDestroyed(); +}; + +class Q_EXPORT QSqlQuery +{ +public: + QSqlQuery( QSqlResult * r ); + QSqlQuery( const QString& query = QString::null, QSqlDatabase* db = 0 ); + Q_EXPLICIT QSqlQuery( QSqlDatabase* db ); + QSqlQuery( const QSqlQuery& other ); + QSqlQuery& operator=( const QSqlQuery& other ); + virtual ~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; + void setForwardOnly( bool forward ); + + virtual bool exec ( const QString& query ); + virtual QVariant value( int i ) const; + + virtual bool seek( int i, bool relative = FALSE ); + virtual bool next(); + virtual bool prev(); + virtual bool first(); + virtual bool last(); + + // prepared query support + bool exec(); + bool prepare( const QString& query ); + void bindValue( const QString& placeholder, const QVariant& val ); + void bindValue( int pos, const QVariant& val ); + void addBindValue( const QVariant& val ); + // remove these overloads in 4.0 + void bindValue( const QString& placeholder, const QVariant& val, QSql::ParameterType type ); + void bindValue( int pos, const QVariant& val, QSql::ParameterType type ); + void addBindValue( const QVariant& val, QSql::ParameterType type ); + QVariant boundValue( const QString& placeholder ) const; + QVariant boundValue( int pos ) const; + QMap<QString, QVariant> boundValues() const; + QString executedQuery() const; + +protected: + virtual void beforeSeek(); + virtual void afterSeek(); + +private: + void init( const QString& query, QSqlDatabase* db ); + void deref(); + bool checkDetach(); + QSqlResultShared* d; +}; + + +#endif // QT_NO_SQL +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlrecord.cpp b/main/dependencies/qt3/src/sql/qsqlrecord.cpp new file mode 100644 index 000000000..bc6a25f90 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlrecord.cpp @@ -0,0 +1,774 @@ +/**************************************************************************** +** +** Implementation of QSqlRecord class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlrecord.h" + +#ifndef QT_NO_SQL + +#include "qregexp.h" +#include "qvaluevector.h" +#include "qshared.h" +#include "qnamespace.h" + +class QSqlRecordPrivate +{ +public: + class info { + public: + info() : nogen(FALSE){} + ~info() {} + info( const info& other ) + : field( other.field ), nogen( other.nogen ) + { + } + info& operator=(const info& other) + { + field = other.field; + nogen = other.nogen; + return *this; + } + bool isValid() const + { + return !field.name().isNull(); + } + Q_DUMMY_COMPARISON_OPERATOR(info) + QSqlField field; + bool nogen; + }; + + QSqlRecordPrivate(): cnt(0) + { + } + QSqlRecordPrivate( const QSqlRecordPrivate& other ) + { + *this = other; + } + ~QSqlRecordPrivate() {}; + QSqlRecordPrivate& operator=( const QSqlRecordPrivate& other ) + { + fi = other.fi; + cnt = other.cnt; + return *this; + } + void append( const QSqlField& field ) + { + info i; + i.field = field; + fi.append( i ); + cnt++; + } + void insert( int pos, const QSqlField& field ) + { + info i; + i.field = field; + if ( pos == (int)fi.size() ) + append( field ); + if ( pos > (int)fi.size() ) { + fi.resize( pos + 1 ); + cnt++; + } + fi[ pos ] = i; + } + void remove( int i ) + { + info inf; + if ( i >= (int)fi.count() ) + return; + if ( fi[ i ].isValid() ) + cnt--; + fi[ i ] = inf; + // clean up some memory + while ( fi.count() && !fi.back().isValid() ) + fi.pop_back(); + } + void clear() + { + fi.clear(); + cnt = 0; + } + bool isEmpty() + { + return cnt == 0; + } + info* fieldInfo( int i ) + { + if ( i < (int)fi.count() ) + return &fi[i]; + return 0; + } + uint count() const + { + return cnt; + } + bool contains( int i ) const + { + return i >= 0 && i < (int)fi.count() && fi[ i ].isValid(); + } +private: + QValueVector< info > fi; + uint cnt; +}; + +QSqlRecordShared::~QSqlRecordShared() +{ + if ( d ) + delete d; +} + +/*! + \class QSqlRecord qsqlfield.h + \brief The QSqlRecord class encapsulates a database record, i.e. a + set of database fields. + + \ingroup database + \module sql + + The QSqlRecord class encapsulates the functionality and + characteristics of a database record (usually a table or view within + the database). QSqlRecords support adding and removing fields as + well as setting and retrieving field values. + + QSqlRecord is implicitly shared. This means you can make copies of + the record in time O(1). If multiple QSqlRecord instances share + the same data and one is modifying the record's data then this + modifying instance makes a copy and modifies its private copy - + thus it does not affect other instances. + + \sa QSqlRecordInfo +*/ + + +/*! + Constructs an empty record. +*/ + +QSqlRecord::QSqlRecord() +{ + sh = new QSqlRecordShared( new QSqlRecordPrivate() ); +} + +/*! + Constructs a copy of \a other. +*/ + +QSqlRecord::QSqlRecord( const QSqlRecord& other ) + : sh( other.sh ) +{ + sh->ref(); +} + +/*! + Sets the record equal to \a other. +*/ + +QSqlRecord& QSqlRecord::operator=( const QSqlRecord& other ) +{ + other.sh->ref(); + deref(); + sh = other.sh; + return *this; +} + +/*! \internal +*/ + +void QSqlRecord::deref() +{ + if ( sh->deref() ) { + delete sh; + sh = 0; + } +} + +/*! \internal +*/ + +bool QSqlRecord::checkDetach() +{ + if ( sh->count > 1 ) { + sh->deref(); + sh = new QSqlRecordShared( new QSqlRecordPrivate( *sh->d ) ); + return TRUE; + } + return FALSE; +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QSqlRecord::~QSqlRecord() +{ + deref(); +} + +/*! + Returns the value of the field located at position \a i in the + record. If field \a i does not exist the resultant behaviour is + undefined. + + This function should be used with \l{QSqlQuery}s. When working + with a QSqlCursor the \link QSqlCursor::value() value(const + QString&)\endlink overload which uses field names is more + appropriate. +*/ + +QVariant QSqlRecord::value( int i ) const +{ + const QSqlField * f = field(i); + + if( f ) + return f->value(); + return QVariant(); +} + +/*! + \overload + + Returns the value of the field called \a name in the record. If + field \a name does not exist the resultant behaviour is undefined. +*/ + +QVariant QSqlRecord::value( const QString& name ) const +{ + const QSqlField * f = field( name ); + + if( f ) + return f->value(); + return QVariant(); +} + +/*! + Returns the name of the field at position \a i. If the field does + not exist, QString::null is returned. +*/ + +QString QSqlRecord::fieldName( int i ) const +{ + const QSqlField* f = field( i ); + if ( f ) + return f->name(); + return QString::null; +} + +/*! + 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. +*/ + +int QSqlRecord::position( const QString& name ) const +{ + for ( uint i = 0; i < count(); ++i ) { + if ( fieldName(i).upper() == name.upper() ) + return i; + } +#ifdef QT_CHECK_RANGE + qWarning( "QSqlRecord::position: unable to find field %s", name.latin1() ); +#endif + return -1; +} + +/*! + Returns the field at position \a i within the record, or 0 if it + cannot be found. +*/ + +QSqlField* QSqlRecord::field( int i ) +{ + checkDetach(); + if ( !sh->d->contains( i ) ) { +#ifdef QT_CHECK_RANGE + qWarning( "QSqlRecord::field: index out of range: %d", i ); +#endif + return 0; + } + return &sh->d->fieldInfo( i )->field; +} + +/*! + \overload + + Returns the field called \a name within the record, or 0 if it + cannot be found. Field names are not case-sensitive. +*/ + +QSqlField* QSqlRecord::field( const QString& name ) +{ + checkDetach(); + if ( !sh->d->contains( position( name ) ) ) + return 0; + return &sh->d->fieldInfo( position( name ) )->field; +} + + +/*! + \overload +*/ + +const QSqlField* QSqlRecord::field( int i ) const +{ + if ( !sh->d->contains( i ) ) { +#ifdef QT_CHECK_RANGE + qWarning( "QSqlRecord::field: index out of range: %d", i ); +#endif // QT_CHECK_RANGE + return 0; + } + return &sh->d->fieldInfo( i )->field; +} + +/*! + \overload + + Returns the field called \a name within the record, or 0 if it + cannot be found. Field names are not case-sensitive. +*/ + +const QSqlField* QSqlRecord::field( const QString& name ) const +{ + if( !sh->d->contains( position( name ) ) ) + return 0; + return &sh->d->fieldInfo( position( name ) )->field; +} + +/*! + Append a copy of field \a field to the end of the record. +*/ + +void QSqlRecord::append( const QSqlField& field ) +{ + checkDetach(); + sh->d->append( field ); +} + +/*! + Insert a copy of \a field at position \a pos. If a field already + exists at \a pos, it is removed. +*/ + +void QSqlRecord::insert( int pos, const QSqlField& field ) // ### 4.0: rename to ::replace +{ + checkDetach(); + sh->d->insert( pos, field ); +} + +/*! + Removes the field at \a pos. If \a pos does not exist, nothing + happens. +*/ + +void QSqlRecord::remove( int pos ) +{ + checkDetach(); + sh->d->remove( pos ); +} + +/*! + Removes all the record's fields. + + \sa clearValues() +*/ + +void QSqlRecord::clear() +{ + checkDetach(); + sh->d->clear(); +} + +/*! + Returns TRUE if there are no fields in the record; otherwise + returns FALSE. +*/ + +bool QSqlRecord::isEmpty() const +{ + return sh->d->isEmpty(); +} + + +/*! + Returns TRUE if there is a field in the record called \a name; + otherwise returns FALSE. +*/ + +bool QSqlRecord::contains( const QString& name ) const +{ + for ( uint i = 0; i < count(); ++i ) { + if ( fieldName(i).upper() == name.upper() ) + return TRUE; + } + return FALSE; +} + +/*! + Clears the value of all fields in the record. If \a nullify is + TRUE, (the default is FALSE), each field is set to NULL. +*/ + +void QSqlRecord::clearValues( bool nullify ) +{ + checkDetach(); + int cnt = (int)count(); + int i; + for ( i = 0; i < cnt; ++i ) { + field( i )->clear( nullify ); + } +} + +/*! + 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, e.g. by QSqlCursor. + + \sa isGenerated() +*/ + +void QSqlRecord::setGenerated( const QString& name, bool generated ) +{ + setGenerated( position( name ), generated ); +} + +/*! + \overload + + Sets the generated flag for the field \a i to \a generated. + + \sa isGenerated() +*/ + +void QSqlRecord::setGenerated( int i, bool generated ) +{ + checkDetach(); + if ( !field( i ) ) + return; + sh->d->fieldInfo( i )->nogen = !generated; +} + +/*! + \internal + ### Remove in 4.0 +*/ +bool QSqlRecord::isNull( int i ) +{ + checkDetach(); + QSqlField* f = field( i ); + if ( f ) { + return f->isNull(); + } + return TRUE; +} + +/*! + \internal + ### Remove in 4.0 +*/ +bool QSqlRecord::isNull( const QString& name ) +{ + return isNull( position( name ) ); +} + +/*! + \overload + + Returns TRUE if the field \a i is NULL or if there is no field at + position \a i; otherwise returns FALSE. + + \sa fieldName() +*/ +bool QSqlRecord::isNull( int i ) const +{ + const QSqlField* f = field( i ); + if ( f ) { + return f->isNull(); + } + return TRUE; +} + +/*! + Returns TRUE if the field called \a name is NULL or if there is no + field called \a name; otherwise returns FALSE. + + \sa position() +*/ +bool QSqlRecord::isNull( const QString& name ) const +{ + return isNull( position( name ) ); +} + +/*! + Sets the value of field \a i to NULL. If the field does not exist, + nothing happens. +*/ +void QSqlRecord::setNull( int i ) +{ + checkDetach(); + QSqlField* f = field( i ); + if ( f ) { + f->setNull(); + } +} + +/*! + \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( position( 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( position( name ) ); +} + +/*! + \overload + + Returns TRUE if the record has a field at position \a i and this + field is to be generated (the default); otherwise returns FALSE. + + \sa setGenerated() +*/ +bool QSqlRecord::isGenerated( int i ) const +{ + if ( !field( i ) ) + return FALSE; + return !sh->d->fieldInfo( i )->nogen; +} + + +/*! + Returns a list of all the record's field names as a string + separated by \a sep. + + Note that fields which are not generated are \e not included (see + \l{isGenerated()}). The returned string is suitable, for example, for + generating SQL SELECT statements. If a \a prefix is specified, + e.g. a table name, all fields are prefixed in the form: + + "\a{prefix}.\<fieldname\>" +*/ + +QString QSqlRecord::toString( const QString& prefix, const QString& sep ) const +{ + QString pflist; + bool comma = FALSE; + for ( uint i = 0; i < count(); ++i ){ + if ( isGenerated( field(i)->name() ) ) { + if( comma ) + pflist += sep + " "; + pflist += createField( i, prefix ); + comma = TRUE; + } + } + return pflist; +} + +/*! + Returns a list of all the record's field names, each having the + prefix \a prefix. + + Note that fields which have generated set to FALSE are \e not + included. (See \l{isGenerated()}). If \a prefix is supplied, e.g. + a table name, all fields are prefixed in the form: + + "\a{prefix}.\<fieldname\>" +*/ + +QStringList QSqlRecord::toStringList( const QString& prefix ) const +{ + QStringList s; + for ( uint i = 0; i < count(); ++i ) { + if ( isGenerated( field(i)->name() ) ) + s += createField( i, prefix ); + } + return s; +} + +/*! \internal +*/ + +QString QSqlRecord::createField( int i, const QString& prefix ) const +{ + QString f; + if ( !prefix.isEmpty() ) + f = prefix + "."; + f += field( i )->name(); + return f; +} + +/*! + Returns the number of fields in the record. +*/ + +uint QSqlRecord::count() const +{ + return sh->d->count(); +} + +/*! + Sets the value of the field at position \a i to \a val. If the + field does not exist, nothing happens. +*/ + +void QSqlRecord::setValue( int i, const QVariant& val ) +{ + checkDetach(); + QSqlField* f = field( i ); + if ( f ) { + f->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( position( name ), val ); +} + + +/******************************************/ +/******* QSqlRecordInfo Impl ******/ +/******************************************/ + +/*! + \class QSqlRecordInfo qsqlrecord.h + \brief The QSqlRecordInfo class encapsulates a set of database field meta data. + + \ingroup database + \module sql + + This class is a QValueList that holds a set of database field meta + data. Use contains() to see if a given field name exists in the + record, and use find() to get a QSqlFieldInfo record for a named + field. + + \sa QValueList, QSqlFieldInfo +*/ + + +/*! + Constructs a QSqlRecordInfo object based on the fields in the + QSqlRecord \a other. +*/ +QSqlRecordInfo::QSqlRecordInfo( const QSqlRecord& other ) +{ + for ( uint i = 0; i < other.count(); ++i ) { + push_back( QSqlFieldInfo( *(other.field( i )), other.isGenerated( i ) ) ); + } +} + +/*! + Returns the number of times a field called \a fieldName occurs in + the record. Returns 0 if no field by that name could be found. +*/ +QSqlRecordInfo::size_type QSqlRecordInfo::contains( const QString& fieldName ) const +{ + size_type i = 0; + QString fName = fieldName.upper(); + for( const_iterator it = begin(); it != end(); ++it ) { + if ( (*it).name().upper() == fName ) { + ++i; + } + } + return i; +} + +/*! + Returns a QSqlFieldInfo object for the first field in the record + which has the field name \a fieldName. If no matching field is + found then an empty QSqlFieldInfo object is returned. +*/ +QSqlFieldInfo QSqlRecordInfo::find( const QString& fieldName ) const +{ + QString fName = fieldName.upper(); + for( const_iterator it = begin(); it != end(); ++it ) { + if ( (*it).name().upper() == fName ) { + return *it; + } + } + return QSqlFieldInfo(); +} + +/*! + Returns an empty QSqlRecord based on the field information + in this QSqlRecordInfo. +*/ +QSqlRecord QSqlRecordInfo::toRecord() const +{ + QSqlRecord buf; + for( const_iterator it = begin(); it != end(); ++it ) { + buf.append( (*it).toField() ); + } + return buf; +} + +/*! + \fn QSqlRecordInfo::QSqlRecordInfo() + + Constructs an empty record info object +*/ + +/*! + \fn QSqlRecordInfo::QSqlRecordInfo( const QSqlFieldInfoList& other ) + + Constructs a copy of \a other. +*/ + +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlrecord.h b/main/dependencies/qt3/src/sql/qsqlrecord.h new file mode 100644 index 000000000..0a7d89828 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlrecord.h @@ -0,0 +1,141 @@ +/**************************************************************************** +** +** Definition of QSqlRecord class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLRECORD_H +#define QSQLRECORD_H + +#ifndef QT_H +#include "qstring.h" +#include "qstringlist.h" +#include "qvariant.h" +#include "qsqlfield.h" +#endif // QT_H + +#ifndef QT_NO_SQL + +class QSqlRecordPrivate; + +class QSqlRecordShared : public QShared +{ +public: + QSqlRecordShared( QSqlRecordPrivate* sqlRecordPrivate ) + : d( sqlRecordPrivate ) + {} + virtual ~QSqlRecordShared(); + QSqlRecordPrivate* d; +}; + +class Q_EXPORT QSqlRecord +{ +public: + QSqlRecord(); + QSqlRecord( const QSqlRecord& other ); + QSqlRecord& operator=( const QSqlRecord& other ); + virtual ~QSqlRecord(); + virtual QVariant value( int i ) const; + virtual QVariant value( const QString& name ) const; + virtual void setValue( int i, const QVariant& val ); + virtual void setValue( const QString& name, const QVariant& val ); + bool isGenerated( int i ) const; + bool isGenerated( const QString& name ) const; + virtual void setGenerated( const QString& name, bool generated ); + virtual void setGenerated( int i, bool generated ); + virtual void setNull( int i ); + virtual void setNull( const QString& name ); + bool isNull( int i ); // remove in 4.0 + bool isNull( const QString& name ); // remove in 4.0 + bool isNull( int i ) const; + bool isNull( const QString& name ) const; + + int position( const QString& name ) const; + QString fieldName( int i ) const; + QSqlField* field( int i ); + QSqlField* field( const QString& name ); + const QSqlField* field( int i ) const; + const QSqlField* field( const QString& name ) const; + + virtual void append( const QSqlField& field ); + virtual void insert( int pos, const QSqlField& field ); + virtual void remove( int pos ); + + bool isEmpty() const; + bool contains( const QString& name ) const; + virtual void clear(); + virtual void clearValues( bool nullify = FALSE ); + uint count() const; + virtual QString toString( const QString& prefix = QString::null, + const QString& sep = "," ) const; + virtual QStringList toStringList( const QString& prefix = QString::null ) const; + +private: + QString createField( int i, const QString& prefix ) const; + void deref(); + bool checkDetach(); + QSqlRecordShared* sh; +}; + +/******************************************/ +/******* QSqlRecordInfo Class ******/ +/******************************************/ + +#if defined(Q_TEMPLATEDLL) +// MOC_SKIP_BEGIN +Q_TEMPLATE_EXTERN template class Q_EXPORT QValueList<QSqlFieldInfo>; +// MOC_SKIP_END +#endif + +typedef QValueList<QSqlFieldInfo> QSqlFieldInfoList; + +class Q_EXPORT QSqlRecordInfo: public QSqlFieldInfoList +{ +public: + QSqlRecordInfo(): QSqlFieldInfoList() {} + QSqlRecordInfo( const QSqlFieldInfoList& other ): QSqlFieldInfoList( other ) {} + QSqlRecordInfo( const QSqlRecord& other ); + + size_type contains( const QString& fieldName ) const; + QSqlFieldInfo find( const QString& fieldName ) const; + QSqlRecord toRecord() const; + +}; + + +#endif // QT_NO_SQL +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlresult.cpp b/main/dependencies/qt3/src/sql/qsqlresult.cpp new file mode 100644 index 000000000..1ec963ffa --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlresult.cpp @@ -0,0 +1,368 @@ +/**************************************************************************** +** +** Implementation of QSqlResult class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlresult.h" +#include "private/qsqlextension_p.h" + +#ifndef QT_NO_SQL + +class QSqlResultPrivate +{ +public: + const QSqlDriver* sqldriver; + int idx; + QString sql; + bool active; + bool isSel; + QSqlError error; + QSqlExtension * ext; +}; + +/*! + \class QSqlResult + \brief The QSqlResult class provides an abstract interface for + accessing data from SQL databases. + + \ingroup database + \module sql + + Normally you would use QSqlQuery instead of QSqlResult since QSqlQuery + provides a generic wrapper for database-specific implementations of + QSqlResult. + + \sa QSql +*/ + + +/*! + Protected constructor which creates a QSqlResult using database \a + db. The object is initialized to an inactive state. +*/ + +QSqlResult::QSqlResult( const QSqlDriver * db ): forwardOnly( FALSE ) +{ + d = new QSqlResultPrivate(); + d->sqldriver = db; + d->idx = QSql::BeforeFirst; + d->isSel = FALSE; + d->active = FALSE; + d->ext = new QSqlExtension(); +} + +/*! + Destroys the object and frees any allocated resources. +*/ + +QSqlResult::~QSqlResult() +{ + if ( d->ext ) + delete d->ext; + delete d; +} + +/*! + Sets the current query for the result to \a query. The result must + be reset() in order to execute the query on the database. +*/ + +void QSqlResult::setQuery( const QString& query ) +{ + d->sql = query; +} + +/*! + Returns the current SQL query text, or QString::null if there is none. +*/ + +QString QSqlResult::lastQuery() const +{ + return d->sql; +} + +/*! + Returns the current (zero-based) position of the result. +*/ + +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. +*/ + +bool QSqlResult::isValid() const +{ + return ( d->idx != QSql::BeforeFirst && \ + d->idx != QSql::AfterLast ) ? TRUE : FALSE; +} + +/*! + \fn bool QSqlResult::isNull( int i ) + + Returns TRUE if the field at position \a i 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; +} + +/*! + Protected function provided for derived classes to set the + internal (zero-based) result index to \a at. + + \sa at() +*/ + +void QSqlResult::setAt( int at ) +{ + d->idx = at; +} + + +/*! + Protected function provided for derived classes to indicate + whether or not the current statement is a SQL SELECT statement. + The \a s parameter should be TRUE if the statement is a SELECT + statement, or FALSE otherwise. +*/ + +void QSqlResult::setSelect( bool s ) +{ + d->isSel = s; +} + +/*! + Returns TRUE if the current result is from a SELECT statement; + otherwise returns FALSE. +*/ + +bool QSqlResult::isSelect() const +{ + return d->isSel; +} + +/*! + Returns the driver associated with the result. +*/ + +const QSqlDriver* QSqlResult::driver() const +{ + return d->sqldriver; +} + + +/*! + Protected function provided for derived classes to set the + internal active state to the value of \a a. + + \sa isActive() +*/ + +void QSqlResult::setActive( bool a ) +{ + d->active = a; +} + +/*! + Protected function provided for derived classes to set the last + error to the value of \a e. + + \sa lastError() +*/ + +void QSqlResult::setLastError( const QSqlError& e ) +{ + d->error = e; +} + + +/*! + Returns the last error associated with the result. +*/ + +QSqlError QSqlResult::lastError() const +{ + return d->error; +} + +/*! + \fn int QSqlResult::size() + + Returns the size of the result or -1 if it cannot be determined. +*/ + +/*! + \fn int QSqlResult::numRowsAffected() + + Returns the number of rows affected by the last query executed. +*/ + +/*! + \fn QVariant QSqlResult::data( int i ) + + Returns the data for field \a i (zero-based) 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 i is non-negative. + Derived classes must reimplement this function and return the value + of field \a i, 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 called only + 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. +*/ + +/*! + \fn bool QSqlResult::fetch( int i ) + + Positions the result to an arbitrary (zero-based) index \a i. 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 + index \a i, and call setAt() with an appropriate value. Return TRUE + to indicate success, or FALSE to signify failure. +*/ + +/*! + \fn bool QSqlResult::fetchFirst() + + Positions the result to the first record 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. +*/ + +/*! + \fn bool QSqlResult::fetchLast() + + Positions the result to the last record 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. +*/ + +/*! + Positions the result to the next available record 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. +*/ + +bool QSqlResult::fetchNext() +{ + return fetch( at() + 1 ); +} + +/*! + Positions the result to the previous available record 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::fetchPrev() +{ + return fetch( at() - 1 ); +} + +/*! + Returns TRUE if you can only scroll forward through a result set; + otherwise returns FALSE. +*/ +bool QSqlResult::isForwardOnly() const +{ + return forwardOnly; +} + +/*! + Sets forward only mode to \a forward. If forward is TRUE only + fetchNext() is allowed for navigating the results. Forward only + mode needs far less memory since results do not have to be cached. + forward only mode is off by default. + + \sa fetchNext() +*/ +void QSqlResult::setForwardOnly( bool forward ) +{ + forwardOnly = forward; +} + +// XXX BCI HACK - remove in 4.0 +/*! \internal */ +void QSqlResult::setExtension( QSqlExtension * ext ) +{ + if ( d->ext ) + delete d->ext; + d->ext = ext; +} + +/*! \internal */ +QSqlExtension * QSqlResult::extension() +{ + return d->ext; +} +#endif // QT_NO_SQL diff --git a/main/dependencies/qt3/src/sql/qsqlresult.h b/main/dependencies/qt3/src/sql/qsqlresult.h new file mode 100644 index 000000000..c0f2ce564 --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlresult.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** Definition of QSqlResult class +** +** Created : 2000-11-03 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLRESULT_H +#define QSQLRESULT_H + +#ifndef QT_H +#include "qstring.h" +#include "qvariant.h" +#include "qsqlerror.h" +#include "qsqlfield.h" +#include "qsql.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL + +class QSqlDriver; +class QSql; +class QSqlResultPrivate; +class QSqlExtension; + +class QM_EXPORT_SQL QSqlResult +{ +friend class QSqlQuery; +friend class QSqlResultShared; +public: + virtual ~QSqlResult(); + + // BCI HACK - remove in 4.0 + void setExtension( QSqlExtension * ext ); + QSqlExtension * extension(); + +protected: + 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 ); + + 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 fetchPrev(); + virtual bool fetchFirst() = 0; + virtual bool fetchLast() = 0; + virtual int size() = 0; + virtual int numRowsAffected() = 0; +private: + QSqlResultPrivate* d; + bool forwardOnly; + +private: // Disabled copy constructor and operator= +#if defined(Q_DISABLE_COPY) + QSqlResult( const QSqlResult & ); + QSqlResult &operator=( const QSqlResult & ); +#endif +}; + +#endif // QT_NO_SQL +#endif diff --git a/main/dependencies/qt3/src/sql/qsqlselectcursor.cpp b/main/dependencies/qt3/src/sql/qsqlselectcursor.cpp new file mode 100644 index 000000000..eeb318ced --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlselectcursor.cpp @@ -0,0 +1,249 @@ +/**************************************************************************** +** +** Definition of QSqlSelectCursor class +** +** Created : 2002-11-13 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#include "qsqlselectcursor.h" +#include "qsqldriver.h" + +#ifndef QT_NO_SQL + +class QSqlSelectCursorPrivate +{ +public: + QSqlSelectCursorPrivate() : populated( FALSE ) {} + QString query; + bool populated : 1; +}; + +/*! + \class QSqlSelectCursor qsqlselectcursor.h + \brief The QSqlSelectCursor class provides browsing of general SQL + SELECT statements. + + \ingroup database + \module sql + + QSqlSelectCursor is a convenience class that makes it possible to + display result sets from general SQL \c SELECT statements in + data-aware Qt widgets. QSqlSelectCursor is read-only and does not + support \c INSERT, \c UPDATE or \c DELETE operations. + + Pass the query in at construction time, or use the + QSqlSelectCursor::exec() function. + + Example: + \code + ... + QSqlSelectCursor* cur = new QSqlSelectCursor( "SELECT id, firstname, lastname FROM author" ); + QDataTable* table = new QDataTable( this ); + table->setSqlCursor( cur, TRUE, TRUE ); + table->refresh(); + ... + cur->exec( "SELECT * FROM books" ); + table->refresh(); + ... + \endcode +*/ + +/*! + Constructs a read only cursor on database \a db using the query \a query. + */ +QSqlSelectCursor::QSqlSelectCursor( const QString& query, QSqlDatabase* db ) + : QSqlCursor( QString::null, FALSE, db ) +{ + d = new QSqlSelectCursorPrivate; + d->query = query; + QSqlCursor::setMode( ReadOnly ); + if ( !query.isNull() ) + exec( query ); +} + +/*! Constructs a copy of \a other */ +QSqlSelectCursor::QSqlSelectCursor( const QSqlSelectCursor& other ) + : QSqlCursor( other ) +{ + d = new QSqlSelectCursorPrivate; + d->query = other.d->query; + d->populated = other.d->populated; +} + +/*! Destroys the object and frees any allocated resources */ +QSqlSelectCursor::~QSqlSelectCursor() +{ + delete d; +} + +/*! \reimp */ +bool QSqlSelectCursor::exec( const QString& query ) +{ + d->query = query; + bool ret = QSqlCursor::exec( query ); + if ( ret ) { + QSqlCursor::clear(); + populateCursor(); + } + return ret; +} + +/*! \fn bool QSqlSelectCursor::select() + \reimp +*/ + +/*! \reimp */ +bool QSqlSelectCursor::select( const QString&, const QSqlIndex& ) +{ + bool ret = QSqlCursor::exec( d->query ); + if ( ret && !d->populated ) + populateCursor(); + return ret; +} + +/*! \internal */ +void QSqlSelectCursor::populateCursor() +{ + QSqlRecordInfo inf = driver()->recordInfo( *(QSqlQuery*)this ); + for ( QSqlRecordInfo::const_iterator it = inf.begin(); it != inf.end(); ++it ) + QSqlCursor::append( *it ); + d->populated = TRUE; +} + +/*! \fn QSqlIndex QSqlSelectCursor::primaryIndex( bool ) const + \reimp +*/ + +/*! \fn QSqlIndex QSqlSelectCursor::index( const QStringList& ) const + \reimp +*/ + +/*! \fn QSqlIndex QSqlSelectCursor::index( const QString& ) const + \reimp +*/ + +/*! \fn QSqlIndex QSqlSelectCursor::index( const char* ) const + \reimp +*/ + +/*! \fn void QSqlSelectCursor::setPrimaryIndex( const QSqlIndex& ) + \reimp +*/ + +/*! \fn void QSqlSelectCursor::append( const QSqlFieldInfo& ) + \reimp +*/ + +/*! \fn void QSqlSelectCursor::insert( int, const QSqlFieldInfo& ) + \reimp +*/ + +/*! \fn void QSqlSelectCursor::remove( int ) + \reimp +*/ + +/*! \fn void QSqlSelectCursor::clear() + \reimp +*/ + +/*! \fn void QSqlSelectCursor::setGenerated( const QString&, bool ) + \reimp +*/ + +/*! \fn void QSqlSelectCursor::setGenerated( int, bool ) + \reimp +*/ + +/*! \fn QSqlRecord* QSqlSelectCursor::editBuffer( bool ) + \reimp +*/ + +/*! \fn QSqlRecord* QSqlSelectCursor::primeInsert() + \reimp +*/ + +/*! \fn QSqlRecord* QSqlSelectCursor::primeUpdate() + \reimp +*/ + +/*! \fn QSqlRecord* QSqlSelectCursor::primeDelete() + \reimp +*/ + +/*! \fn int QSqlSelectCursor::insert( bool ) + \reimp +*/ + +/*! \fn int QSqlSelectCursor::update( bool ) + \reimp +*/ + +/*! \fn int QSqlSelectCursor::del( bool ) + \reimp +*/ + +/*! \fn void QSqlSelectCursor::setMode( int ) + \reimp +*/ + +/*! \fn void QSqlSelectCursor::setSort( const QSqlIndex& ) + \reimp +*/ + +/*! \fn QSqlIndex QSqlSelectCursor::sort() const + \reimp +*/ + +/*! \fn void QSqlSelectCursor::setFilter( const QString& ) + \reimp +*/ + +/*! \fn QString QSqlSelectCursor::filter() const + \reimp +*/ + +/*! \fn void QSqlSelectCursor::setName( const QString&, bool ) + \reimp +*/ + +/*! \fn QString QSqlSelectCursor::name() const + \reimp +*/ + +/*! \fn QString QSqlSelectCursor::toString( const QString&, const QString& ) const + \reimp +*/ +#endif // QT_NO_SQL diff --git a/main/dependencies/qt3/src/sql/qsqlselectcursor.h b/main/dependencies/qt3/src/sql/qsqlselectcursor.h new file mode 100644 index 000000000..2204b610d --- /dev/null +++ b/main/dependencies/qt3/src/sql/qsqlselectcursor.h @@ -0,0 +1,104 @@ +/**************************************************************************** +** +** Definition of QSqlSelectCursor class +** +** Created : 2002-11-13 +** +** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved. +** +** This file is part of the sql module of the Qt GUI Toolkit. +** +** This file may be used under the terms of the GNU General +** Public License versions 2.0 or 3.0 as published by the Free +** Software Foundation and appearing in the files LICENSE.GPL2 +** and LICENSE.GPL3 included in the packaging of this file. +** Alternatively you may (at your option) use any later version +** of the GNU General Public License if such license has been +** publicly approved by Trolltech ASA (or its successors, if any) +** and the KDE Free Qt Foundation. +** +** 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. +** +** This file may be used under the terms of the Q Public License as +** defined by Trolltech ASA and appearing in the file LICENSE.QPL +** included in the packaging of this file. Licensees holding valid Qt +** Commercial licenses may use this file in accordance with the Qt +** Commercial License Agreement provided with the Software. +** +** This file is provided "AS IS" with NO WARRANTY OF ANY KIND, +** INCLUDING THE WARRANTIES OF DESIGN, MERCHANTABILITY AND FITNESS FOR +** A PARTICULAR PURPOSE. Trolltech reserves all rights not granted +** herein. +** +**********************************************************************/ + +#ifndef QSQLSELECTCURSOR_H +#define QSQLSELECTCURSOR_H + +#ifndef QT_H +#include "qsqlcursor.h" +#endif // QT_H + +#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL ) +#define QM_EXPORT_SQL +#else +#define QM_EXPORT_SQL Q_EXPORT +#endif + +#ifndef QT_NO_SQL + +class QSqlSelectCursorPrivate; + +class QM_EXPORT_SQL QSqlSelectCursor : public QSqlCursor +{ +public: + QSqlSelectCursor( const QString& query = QString::null, QSqlDatabase* db = 0 ); + QSqlSelectCursor( const QSqlSelectCursor& other ); + ~QSqlSelectCursor(); + bool exec( const QString& query ); + bool select() { return QSqlCursor::select(); } + +protected: + QSqlIndex primaryIndex( bool = TRUE ) const { return QSqlIndex(); } + QSqlIndex index( const QStringList& ) const { return QSqlIndex(); } + QSqlIndex index( const QString& ) const { return QSqlIndex(); } + QSqlIndex index( const char* ) const { return QSqlIndex(); } + void setPrimaryIndex( const QSqlIndex& ) {} + void append( const QSqlFieldInfo& ) {} + void insert( int, const QSqlFieldInfo& ) {} + void remove( int ) {} + void clear() {} + void setGenerated( const QString&, bool ) {} + void setGenerated( int, bool ) {} + QSqlRecord* editBuffer( bool = FALSE ) { return 0; } + QSqlRecord* primeInsert() { return 0; } + QSqlRecord* primeUpdate() { return 0; } + QSqlRecord* primeDelete() { return 0; } + int insert( bool = TRUE ) { return 0; } + int update( bool = TRUE ) { return 0; } + int del( bool = TRUE ) { return 0; } + void setMode( int ) {} + + void setSort( const QSqlIndex& ) {} + QSqlIndex sort() const { return QSqlIndex(); } + void setFilter( const QString& ) {} + QString filter() const { return QString::null; } + void setName( const QString&, bool = TRUE ) {} + QString name() const { return QString::null; } + QString toString( const QString& = QString::null, const QString& = "," ) const { return QString::null; } + bool select( const QString &, const QSqlIndex& = QSqlIndex() ); + +private: + void populateCursor(); + + QSqlSelectCursorPrivate * d; +}; + +#endif // QT_NO_SQL +#endif // QSQLSELECTCURSOR_H diff --git a/main/dependencies/qt3/src/sql/qt_sql.pri b/main/dependencies/qt3/src/sql/qt_sql.pri new file mode 100644 index 000000000..5533c6fbe --- /dev/null +++ b/main/dependencies/qt3/src/sql/qt_sql.pri @@ -0,0 +1,254 @@ +# Qt sql module + +sql { + + !table { + message(table must be enabled for sql support) + REQUIRES += table + } + + SQL_P = sql + HEADERS += $$SQL_H/qsql.h \ + $$SQL_H/qsqlquery.h \ + $$SQL_H/qsqldatabase.h \ + $$SQL_H/qsqlfield.h \ + $$SQL_H/qsqlrecord.h \ + $$SQL_H/qsqlcursor.h \ + $$SQL_H/qsqlform.h \ + $$SQL_H/qeditorfactory.h \ + $$SQL_H/qsqleditorfactory.h \ + $$SQL_H/qsqldriver.h \ + $$SQL_P/qsqldriverinterface_p.h \ + $$SQL_P/qsqlextension_p.h \ + $$SQL_H/qsqldriverplugin.h \ + $$SQL_H/qsqlerror.h \ + $$SQL_H/qsqlresult.h \ + $$SQL_H/qsqlindex.h \ + $$SQL_H/qsqlpropertymap.h \ + $$SQL_P/qsqlmanager_p.h \ + $$SQL_H/qdatatable.h \ + $$SQL_H/qdataview.h \ + $$SQL_H/qdatabrowser.h \ + $$SQL_H/qsqlselectcursor.h + + SOURCES += $$SQL_CPP/qsqlquery.cpp \ + $$SQL_CPP/qsqldatabase.cpp \ + $$SQL_CPP/qsqlfield.cpp \ + $$SQL_CPP/qsqlrecord.cpp \ + $$SQL_CPP/qsqlform.cpp \ + $$SQL_CPP/qsqlcursor.cpp \ + $$SQL_CPP/qeditorfactory.cpp \ + $$SQL_CPP/qsqleditorfactory.cpp \ + $$SQL_CPP/qsqldriver.cpp \ + $$SQL_CPP/qsqlextension_p.cpp \ + $$SQL_CPP/qsqldriverplugin.cpp \ + $$SQL_CPP/qsqlerror.cpp \ + $$SQL_CPP/qsqlresult.cpp \ + $$SQL_CPP/qsqlindex.cpp \ + $$SQL_CPP/qsqlpropertymap.cpp \ + $$SQL_CPP/qsqlmanager_p.cpp \ + $$SQL_CPP/qdatatable.cpp \ + $$SQL_CPP/qdataview.cpp \ + $$SQL_CPP/qdatabrowser.cpp \ + $$SQL_CPP/qsqlselectcursor.cpp \ + $$SQL_CPP/drivers/cache/qsqlcachedresult.cpp + + contains(sql-drivers, all ) { + sql-driver += psql mysql odbc oci tds db2 sqlite ibase + } + + contains(sql-drivers, psql) { + HEADERS += $$SQL_CPP/drivers/psql/qsql_psql.h + SOURCES += $$SQL_CPP/drivers/psql/qsql_psql.cpp + DEFINES += QT_SQL_POSTGRES + unix { + !contains( LIBS, .*pq.* ) { + LIBS *= -lpq + } + } + win32 { + !contains( LIBS, .*libpq.* ) { + LIBS *= libpqdll.lib + } +# win32-msvc: { +# LIBS *= delayimp.lib +# QMAKE_LFLAGS += /DELAYLOAD:libpqdll.dll +# } +# win32-borland: { +# QMAKE_LFLAGS += /dlibpqdll.dll +# } + } + } + + contains(sql-drivers, mysql) { + HEADERS += $$SQL_CPP/drivers/mysql/qsql_mysql.h + SOURCES += $$SQL_CPP/drivers/mysql/qsql_mysql.cpp + DEFINES += QT_SQL_MYSQL + unix { + !contains( LIBS, .*mysql.* ) { + LIBS *= -lmysqlclient + } + } + win32 { + !contains( LIBS, .*mysql.* ) { + LIBS *= libmysql.lib + } +# win32-msvc: { +# LIBS *= delayimp.lib +# QMAKE_LFLAGS += /DELAYLOAD:libmysql.dll +# } +# win32-borland: { +# QMAKE_LFLAGS += /dlibmysql.dll +# } + } + } + + contains(sql-drivers, odbc) { + HEADERS += $$SQL_CPP/drivers/odbc/qsql_odbc.h + SOURCES += $$SQL_CPP/drivers/odbc/qsql_odbc.cpp + DEFINES += QT_SQL_ODBC + + mac { + !contains( LIBS, .*odbc.* ) { + LIBS *= -liodbc + } + } + + unix { + !contains( LIBS, .*odbc.* ) { + LIBS *= -liodbc + } + } + + win32 { + !win32-borland:LIBS *= odbc32.lib + win32-borland:LIBS *= $(BCB)/lib/PSDK/odbc32.lib + } + + } + + contains(sql-drivers, oci) { + HEADERS += $$SQL_CPP/drivers/oci/qsql_oci.h + SOURCES += $$SQL_CPP/drivers/oci/qsql_oci.cpp + DEFINES += QT_SQL_OCI + unix { + !contains( LIBS, .*clnts.* ) { + LIBS += -lclntsh -lwtc8 + } + } + win32 { + LIBS += oci.lib +# win32-msvc: { +# LIBS *= delayimp.lib +# QMAKE_LFLAGS += /DELAYLOAD:oci.dll +# } +# win32-borland: { +# QMAKE_LFLAGS += /doci.dll +# } + } + } + + contains(sql-drivers, tds) { + HEADERS += $$SQL_CPP/drivers/tds/qsql_tds.h \ + $$SQL_CPP/drivers/shared/qsql_result.h + SOURCES += $$SQL_CPP/drivers/tds/qsql_tds.cpp \ + $$SQL_CPP/drivers/shared/qsql_result.cpp + DEFINES += QT_SQL_TDS + unix { + LIBS += -L$SYBASE/lib -lsybdb + } + win32 { + !win32-borland:LIBS += NTWDBLIB.LIB + win32-borland:LIBS += $(BCB)/lib/PSDK/NTWDBLIB.LIB +# win32-msvc: { +# LIBS *= delayimp.lib +# QMAKE_LFLAGS += /DELAYLOAD:ntwdblib.dll +# } +# win32-borland: { +# QMAKE_LFLAGS += /dntwdblib.dll +# } + } + } + + contains(sql-drivers, db2) { + HEADERS += $$SQL_CPP/drivers/db2/qsql_db2.h + SOURCES += $$SQL_CPP/drivers/db2/qsql_db2.cpp + DEFINES += QT_SQL_DB2 + unix { + LIBS += -ldb2 + } + win32 { + !win32-borland:LIBS += db2cli.lib +# win32-borland:LIBS += $(BCB)/lib/PSDK/db2cli.lib + } + } + + contains(sql-drivers, ibase) { + HEADERS += $$SQL_CPP/drivers/ibase/qsql_ibase.h + SOURCES += $$SQL_CPP/drivers/ibase/qsql_ibase.cpp + DEFINES += QT_SQL_IBASE + unix { + LIBS *= -lfbclient + } + win32 { + !win32-borland:LIBS *= gds32_ms.lib + win32-borland:LIBS += gds32.lib + } + } + + contains(sql-drivers, sqlite) { + !contains( LIBS, .*sqlite.* ) { + + INCLUDEPATH += $$SQL_CPP/../3rdparty/sqlite/ + + HEADERS += $$SQL_CPP/../3rdparty/sqlite/btree.h \ + $$SQL_CPP/../3rdparty/sqlite/config.h \ + $$SQL_CPP/../3rdparty/sqlite/hash.h \ + $$SQL_CPP/../3rdparty/sqlite/opcodes.h \ + $$SQL_CPP/../3rdparty/sqlite/os.h \ + $$SQL_CPP/../3rdparty/sqlite/pager.h \ + $$SQL_CPP/../3rdparty/sqlite/parse.h \ + $$SQL_CPP/../3rdparty/sqlite/sqlite.h \ + $$SQL_CPP/../3rdparty/sqlite/sqliteInt.h \ + $$SQL_CPP/../3rdparty/sqlite/vdbe.h \ + $$SQL_CPP/../3rdparty/sqlite/vdbeInt.h + + SOURCES += $$SQL_CPP/../3rdparty/sqlite/attach.c \ + $$SQL_CPP/../3rdparty/sqlite/auth.c \ + $$SQL_CPP/../3rdparty/sqlite/btree.c \ + $$SQL_CPP/../3rdparty/sqlite/btree_rb.c \ + $$SQL_CPP/../3rdparty/sqlite/build.c \ + $$SQL_CPP/../3rdparty/sqlite/copy.c \ + $$SQL_CPP/../3rdparty/sqlite/date.c \ + $$SQL_CPP/../3rdparty/sqlite/delete.c \ + $$SQL_CPP/../3rdparty/sqlite/expr.c \ + $$SQL_CPP/../3rdparty/sqlite/func.c \ + $$SQL_CPP/../3rdparty/sqlite/hash.c \ + $$SQL_CPP/../3rdparty/sqlite/insert.c \ + $$SQL_CPP/../3rdparty/sqlite/main.c \ + $$SQL_CPP/../3rdparty/sqlite/opcodes.c \ + $$SQL_CPP/../3rdparty/sqlite/os.c \ + $$SQL_CPP/../3rdparty/sqlite/pager.c \ + $$SQL_CPP/../3rdparty/sqlite/parse.c \ + $$SQL_CPP/../3rdparty/sqlite/pragma.c \ + $$SQL_CPP/../3rdparty/sqlite/printf.c \ + $$SQL_CPP/../3rdparty/sqlite/random.c \ + $$SQL_CPP/../3rdparty/sqlite/select.c \ + $$SQL_CPP/../3rdparty/sqlite/shell.c \ + $$SQL_CPP/../3rdparty/sqlite/table.c \ + $$SQL_CPP/../3rdparty/sqlite/tokenize.c \ + $$SQL_CPP/../3rdparty/sqlite/trigger.c \ + $$SQL_CPP/../3rdparty/sqlite/update.c \ + $$SQL_CPP/../3rdparty/sqlite/util.c \ + $$SQL_CPP/../3rdparty/sqlite/vacuum.c \ + $$SQL_CPP/../3rdparty/sqlite/vdbe.c \ + $$SQL_CPP/../3rdparty/sqlite/vdbeaux.c \ + $$SQL_CPP/../3rdparty/sqlite/where.c + } + + HEADERS += $$SQL_CPP/drivers/sqlite/qsql_sqlite.h + SOURCES += $$SQL_CPP/drivers/sqlite/qsql_sqlite.cpp + DEFINES += QT_SQL_SQLITE + } +} + |