summaryrefslogtreecommitdiffstats
path: root/src/sql
diff options
context:
space:
mode:
Diffstat (limited to 'src/sql')
-rw-r--r--src/sql/README.module37
-rw-r--r--src/sql/drivers/cache/qsqlcachedresult.cpp259
-rw-r--r--src/sql/drivers/cache/qsqlcachedresult.h104
-rw-r--r--src/sql/drivers/ibase/qsql_ibase.cpp1078
-rw-r--r--src/sql/drivers/ibase/qsql_ibase.h117
-rw-r--r--src/sql/drivers/mysql/qsql_mysql.cpp775
-rw-r--r--src/sql/drivers/mysql/qsql_mysql.h131
-rw-r--r--src/sql/drivers/odbc/debian_qsql_odbc.h10
-rw-r--r--src/sql/drivers/odbc/qsql_odbc.cpp2035
-rw-r--r--src/sql/drivers/odbc/qsql_odbc.h162
-rw-r--r--src/sql/drivers/psql/qsql_psql.cpp1117
-rw-r--r--src/sql/drivers/psql/qsql_psql.h131
-rw-r--r--src/sql/drivers/sqlite/qsql_sqlite.cpp513
-rw-r--r--src/sql/drivers/sqlite/qsql_sqlite.h90
-rw-r--r--src/sql/qdatabrowser.cpp1284
-rw-r--r--src/sql/qdatabrowser.h177
-rw-r--r--src/sql/qdatatable.cpp2322
-rw-r--r--src/sql/qdatatable.h244
-rw-r--r--src/sql/qdataview.cpp208
-rw-r--r--src/sql/qdataview.h90
-rw-r--r--src/sql/qeditorfactory.cpp192
-rw-r--r--src/sql/qeditorfactory.h76
-rw-r--r--src/sql/qsql.cpp114
-rw-r--r--src/sql/qsql.h100
-rw-r--r--src/sql/qsqlcursor.cpp1549
-rw-r--r--src/sql/qsqlcursor.h160
-rw-r--r--src/sql/qsqldatabase.cpp1332
-rw-r--r--src/sql/qsqldatabase.h155
-rw-r--r--src/sql/qsqldriver.cpp509
-rw-r--r--src/sql/qsqldriver.h125
-rw-r--r--src/sql/qsqldriverinterface_p.h85
-rw-r--r--src/sql/qsqldriverplugin.cpp161
-rw-r--r--src/sql/qsqldriverplugin.h72
-rw-r--r--src/sql/qsqleditorfactory.cpp221
-rw-r--r--src/sql/qsqleditorfactory.h77
-rw-r--r--src/sql/qsqlerror.cpp228
-rw-r--r--src/sql/qsqlerror.h93
-rw-r--r--src/sql/qsqlextension_p.cpp169
-rw-r--r--src/sql/qsqlextension_p.h148
-rw-r--r--src/sql/qsqlfield.cpp563
-rw-r--r--src/sql/qsqlfield.h154
-rw-r--r--src/sql/qsqlform.cpp403
-rw-r--r--src/sql/qsqlform.h108
-rw-r--r--src/sql/qsqlindex.cpp301
-rw-r--r--src/sql/qsqlindex.h99
-rw-r--r--src/sql/qsqlmanager_p.cpp941
-rw-r--r--src/sql/qsqlmanager_p.h163
-rw-r--r--src/sql/qsqlpropertymap.cpp304
-rw-r--r--src/sql/qsqlpropertymap.h78
-rw-r--r--src/sql/qsqlquery.cpp1215
-rw-r--r--src/sql/qsqlquery.h133
-rw-r--r--src/sql/qsqlrecord.cpp774
-rw-r--r--src/sql/qsqlrecord.h141
-rw-r--r--src/sql/qsqlresult.cpp368
-rw-r--r--src/sql/qsqlresult.h115
-rw-r--r--src/sql/qsqlselectcursor.cpp249
-rw-r--r--src/sql/qsqlselectcursor.h104
-rw-r--r--src/sql/qt_sql.pri254
58 files changed, 22917 insertions, 0 deletions
diff --git a/src/sql/README.module b/src/sql/README.module
new file mode 100644
index 000000000..308098bf9
--- /dev/null
+++ b/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 retquire 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/src/sql/drivers/cache/qsqlcachedresult.cpp b/src/sql/drivers/cache/qsqlcachedresult.cpp
new file mode 100644
index 000000000..5e46b9b49
--- /dev/null
+++ b/src/sql/drivers/cache/qsqlcachedresult.cpp
@@ -0,0 +1,259 @@
+/****************************************************************************
+**
+** Implementation of cached TQt SQL result classes
+**
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQtSqlCachedResultPrivate
+{
+public:
+ TQtSqlCachedResultPrivate();
+ bool seek(int i);
+ void init(int count, bool fo);
+ void cleanup();
+ TQtSqlCachedResult::RowCache* next();
+ void revertLast();
+
+ TQtSqlCachedResult::RowsetCache *cache;
+ TQtSqlCachedResult::RowCache *current;
+ int rowCacheEnd;
+ int colCount;
+ bool forwardOnly;
+};
+
+TQtSqlCachedResultPrivate::TQtSqlCachedResultPrivate():
+ cache(0), current(0), rowCacheEnd(0), colCount(0), forwardOnly(FALSE)
+{
+}
+
+void TQtSqlCachedResultPrivate::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 TQtSqlCachedResultPrivate::init(int count, bool fo)
+{
+ cleanup();
+ forwardOnly = fo;
+ colCount = count;
+ if (fo)
+ current = new TQtSqlCachedResult::RowCache(count);
+ else
+ cache = new TQtSqlCachedResult::RowsetCache(initial_cache_size);
+}
+
+TQtSqlCachedResult::RowCache *TQtSqlCachedResultPrivate::next()
+{
+ if (forwardOnly)
+ return current;
+
+ Q_ASSERT(cache);
+ current = new TQtSqlCachedResult::RowCache(colCount);
+ if (rowCacheEnd == (int)cache->size())
+ cache->resize(cache->size() * 2);
+ cache->insert(rowCacheEnd++, current);
+ return current;
+}
+
+bool TQtSqlCachedResultPrivate::seek(int i)
+{
+ if (forwardOnly || i < 0)
+ return FALSE;
+ if (i >= rowCacheEnd)
+ return FALSE;
+ current = (*cache)[i];
+ return TRUE;
+}
+
+void TQtSqlCachedResultPrivate::revertLast()
+{
+ if (forwardOnly)
+ return;
+ --rowCacheEnd;
+ delete current;
+ current = 0;
+}
+
+//////////////
+
+TQtSqlCachedResult::TQtSqlCachedResult(const TQSqlDriver * db ): TQSqlResult ( db )
+{
+ d = new TQtSqlCachedResultPrivate();
+}
+
+TQtSqlCachedResult::~TQtSqlCachedResult()
+{
+ delete d;
+}
+
+void TQtSqlCachedResult::init(int colCount)
+{
+ d->init(colCount, isForwardOnly());
+}
+
+bool TQtSqlCachedResult::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() == TQSql::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 TQtSqlCachedResult::fetchNext()
+{
+ if (d->seek(at() + 1)) {
+ setAt(at() + 1);
+ return TRUE;
+ }
+ return cacheNext();
+}
+
+bool TQtSqlCachedResult::fetchPrev()
+{
+ return fetch(at() - 1);
+}
+
+bool TQtSqlCachedResult::fetchFirst()
+{
+ if (d->forwardOnly && at() != TQSql::BeforeFirst) {
+ return FALSE;
+ }
+ if (d->seek(0)) {
+ setAt(0);
+ return TRUE;
+ }
+ return cacheNext();
+}
+
+bool TQtSqlCachedResult::fetchLast()
+{
+ if (at() == TQSql::AfterLast) {
+ if (d->forwardOnly)
+ return FALSE;
+ else
+ return fetch(d->rowCacheEnd - 1);
+ }
+
+ int i = at();
+ while (fetchNext())
+ i++; /* brute force */
+ if (d->forwardOnly && at() == TQSql::AfterLast) {
+ setAt(i);
+ return TRUE;
+ } else {
+ return fetch(d->rowCacheEnd - 1);
+ }
+}
+
+TQVariant TQtSqlCachedResult::data(int i)
+{
+ if (!d->current || i >= (int)d->current->size() || i < 0)
+ return TQVariant();
+
+ return (*d->current)[i];
+}
+
+bool TQtSqlCachedResult::isNull(int i)
+{
+ if (!d->current || i >= (int)d->current->size() || i < 0)
+ return TRUE;
+
+ return (*d->current)[i].isNull();
+}
+
+void TQtSqlCachedResult::cleanup()
+{
+ setAt(TQSql::BeforeFirst);
+ setActive(FALSE);
+ d->cleanup();
+}
+
+bool TQtSqlCachedResult::cacheNext()
+{
+ if (!gotoNext(d->next())) {
+ d->revertLast();
+ return FALSE;
+ }
+ setAt(at() + 1);
+ return TRUE;
+}
+
+int TQtSqlCachedResult::colCount() const
+{
+ return d->colCount;
+}
+#endif // QT_NO_SQL
diff --git a/src/sql/drivers/cache/qsqlcachedresult.h b/src/sql/drivers/cache/qsqlcachedresult.h
new file mode 100644
index 000000000..1cdae7ae2
--- /dev/null
+++ b/src/sql/drivers/cache/qsqlcachedresult.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Definition of shared TQt SQL module classes
+**
+** Copyright (C) 1992-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLCACHEDRESULT_H
+#define TQSQLCACHEDRESULT_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the TQt API. It exists for the convenience
+// of other TQt 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 TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL
+
+class TQtSqlCachedResultPrivate;
+
+class TQM_EXPORT_SQL TQtSqlCachedResult: public TQSqlResult
+{
+public:
+ virtual ~TQtSqlCachedResult();
+
+ typedef TQValueVector<TQVariant> RowCache;
+ typedef TQPtrVector<RowCache> RowsetCache;
+
+protected:
+ TQtSqlCachedResult(const TQSqlDriver * db);
+
+ void init(int colCount);
+ void cleanup();
+ bool cacheNext();
+
+ virtual bool gotoNext(RowCache* row) = 0;
+
+ TQVariant data(int i);
+ bool isNull(int i);
+ bool fetch(int i);
+ bool fetchNext();
+ bool fetchPrev();
+ bool fetchFirst();
+ bool fetchLast();
+
+ int colCount() const;
+
+private:
+ TQtSqlCachedResultPrivate *d;
+};
+
+
+#endif
+
+#endif
diff --git a/src/sql/drivers/ibase/qsql_ibase.cpp b/src/sql/drivers/ibase/qsql_ibase.cpp
new file mode 100644
index 000000000..22c41064d
--- /dev/null
+++ b/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 TQt 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 TQIBASE_DRIVER_NAME "TQIBASE"
+
+class TQIBasePreparedExtension : public TQSqlExtension
+{
+public:
+ TQIBasePreparedExtension(TQIBaseResult *r)
+ : result(r) {}
+
+ bool prepare(const TQString &query)
+ {
+ return result->prepare(query);
+ }
+
+ bool exec()
+ {
+ return result->exec();
+ }
+
+ TQIBaseResult *result;
+};
+
+static bool getIBaseError(TQString& 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 = TQString::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 TQVariant::Type qIBaseTypeName(int iType)
+{
+ switch (iType) {
+ case blr_varying:
+ case blr_varying2:
+ case blr_text:
+ case blr_cstring:
+ case blr_cstring2:
+ return TQVariant::String;
+ case blr_sql_time:
+ return TQVariant::Time;
+ case blr_sql_date:
+ return TQVariant::Date;
+ case blr_timestamp:
+ return TQVariant::DateTime;
+ case blr_blob:
+ return TQVariant::ByteArray;
+ case blr_quad:
+ case blr_short:
+ case blr_long:
+ return TQVariant::Int;
+ case blr_int64:
+ return TQVariant::LongLong;
+ case blr_float:
+ case blr_d_float:
+ case blr_double:
+ return TQVariant::Double;
+ }
+ return TQVariant::Invalid;
+}
+
+static TQVariant::Type qIBaseTypeName2(int iType)
+{
+ switch(iType & ~1) {
+ case SQL_VARYING:
+ case SQL_TEXT:
+ return TQVariant::String;
+ case SQL_LONG:
+ case SQL_SHORT:
+ return TQVariant::Int;
+ case SQL_INT64:
+ return TQVariant::LongLong;
+ case SQL_FLOAT:
+ case SQL_DOUBLE:
+ return TQVariant::Double;
+ case SQL_TIMESTAMP:
+ return TQVariant::DateTime;
+ case SQL_TYPE_DATE:
+ return TQVariant::Date;
+ case SQL_TYPE_TIME:
+ return TQVariant::Time;
+ default:
+ return TQVariant::Invalid;
+ }
+}
+
+static ISC_TIME toTime(const TQTime &t)
+{
+ static const TQTime midnight(0, 0, 0, 0);
+ return (ISC_TIME)midnight.msecsTo(t) * 10;
+}
+
+static ISC_DATE toDate(const TQDate &d)
+{
+ static const TQDate basedate(1858, 11, 17);
+ return (ISC_DATE)basedate.daysTo(d);
+}
+
+static ISC_TIMESTAMP toTimeStamp(const TQDateTime &dt)
+{
+ ISC_TIMESTAMP ts;
+ ts.timestamp_time = toTime(dt.time());
+ ts.timestamp_date = toDate(dt.date());
+ return ts;
+}
+
+static TQTime toTQTime(ISC_TIME time)
+{
+ // have to demangle the structure ourselves because isc_decode_time
+ // strips the msecs
+ static const TQTime t;
+ return t.addMSecs(time / 10);
+}
+
+static TQDate toTQDate(ISC_DATE d)
+{
+ static const TQDate bd(1858, 11, 17);
+ return bd.addDays(d);
+}
+
+static TQDateTime toTQDateTime(ISC_TIMESTAMP *ts)
+{
+ return TQDateTime(toTQDate(ts->timestamp_date), toTQTime(ts->timestamp_time));
+}
+
+class TQIBaseDriverPrivate
+{
+public:
+ TQIBaseDriverPrivate(TQIBaseDriver *d): q(d)
+ {
+ ibase = 0;
+ trans = 0;
+ }
+
+ bool isError(const TQString &msg = TQString::null, TQSqlError::Type typ = TQSqlError::Unknown)
+ {
+ TQString imsg;
+ long sqlcode;
+ if (!getIBaseError(imsg, status, sqlcode))
+ return FALSE;
+
+ q->setLastError(TQSqlError(msg, imsg, typ, (int)sqlcode));
+ return TRUE;
+ }
+
+public:
+ TQIBaseDriver* q;
+ isc_db_handle ibase;
+ isc_tr_handle trans;
+ ISC_STATUS status[20];
+};
+
+class TQIBaseResultPrivate
+{
+public:
+ TQIBaseResultPrivate(TQIBaseResult *d, const TQIBaseDriver *ddb);
+ ~TQIBaseResultPrivate() { cleanup(); }
+
+ void cleanup();
+ bool isError(const TQString &msg = TQString::null, TQSqlError::Type typ = TQSqlError::Unknown)
+ {
+ TQString imsg;
+ long sqlcode;
+ if (!getIBaseError(imsg, status, sqlcode))
+ return FALSE;
+
+ q->setLastError(TQSqlError(msg, imsg, typ, (int)sqlcode));
+ return TRUE;
+ }
+
+ bool transaction();
+ bool commit();
+
+ bool isSelect();
+ TQVariant fetchBlob(ISC_QUAD *bId);
+ void writeBlob(int i, const TQByteArray &ba);
+
+public:
+ TQIBaseResult *q;
+ const TQIBaseDriver *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;
+};
+
+TQIBaseResultPrivate::TQIBaseResultPrivate(TQIBaseResult *d, const TQIBaseDriver *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 TQIBaseResultPrivate::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 TQIBaseResultPrivate::writeBlob(int i, const TQByteArray &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", TQSqlError::Statement)) {
+ uint i = 0;
+ while (i < ba.size()) {
+ isc_put_segment(status, &handle, TQMIN(ba.size() - i, SHRT_MAX), ba.data());
+ if (isError("Unable to write BLOB"))
+ break;
+ i += SHRT_MAX;
+ }
+ }
+ isc_close_blob(status, &handle);
+}
+
+TQVariant TQIBaseResultPrivate::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", TQSqlError::Statement))
+ return TQVariant();
+
+ unsigned short len = 0;
+ TQByteArray 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(TQMIN(ba.size() * 2, SHRT_MAX));
+ stat = isc_get_segment(status, &handle, &len, osize, ba.data() + osize);
+ }
+ bool isErr = isError("Unable to read BLOB", TQSqlError::Statement);
+ isc_close_blob(status, &handle);
+ if (isErr)
+ return TQVariant();
+
+ if (ba.size() > 255)
+ ba.resize(ba.size() / 2 + len);
+ else
+ ba.resize(len);
+
+ return ba;
+}
+
+bool TQIBaseResultPrivate::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", TQSqlError::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 TQIBaseResultPrivate::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", TQSqlError::Statement))
+ return FALSE;
+
+ return TRUE;
+}
+
+// does nothing if the transaction is on the
+// driver level
+bool TQIBaseResultPrivate::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", TQSqlError::Statement);
+}
+
+//////////
+
+TQIBaseResult::TQIBaseResult(const TQIBaseDriver* db):
+ TQtSqlCachedResult(db)
+{
+ d = new TQIBaseResultPrivate(this, db);
+ setExtension(new TQIBasePreparedExtension(this));
+}
+
+TQIBaseResult::~TQIBaseResult()
+{
+ delete d;
+}
+
+bool TQIBaseResult::prepare(const TQString& query)
+{
+ //qDebug("prepare: %s", query.ascii());
+ if (!driver() || !driver()->isOpen() || driver()->isOpenError())
+ return FALSE;
+ d->cleanup();
+ setActive(FALSE);
+ setAt(TQSql::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", TQSqlError::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", TQSqlError::Statement))
+ return FALSE;
+
+ isc_dsql_describe_bind(d->status, &d->stmt, 1, d->inda);
+ if (d->isError("Could not describe input statement", TQSqlError::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", TQSqlError::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", TQSqlError::Statement))
+ return FALSE;
+ }
+ initDA(d->sqlda);
+
+ setSelect(d->isSelect());
+ if (!isSelect()) {
+ free(d->sqlda);
+ d->sqlda = 0;
+ }
+
+ return TRUE;
+}
+
+bool TQIBaseResult::exec()
+{
+ if (!driver() || !driver()->isOpen() || driver()->isOpenError())
+ return FALSE;
+ setActive(FALSE);
+ setAt(TQSql::BeforeFirst);
+
+ if (d->inda && extension()->index.count() > 0) {
+ TQMap<int, TQString>::ConstIterator it;
+ if ((int)extension()->index.count() > d->inda->sqld) {
+ qWarning("TQIBaseResult::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 TQVariant 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: {
+ TQCString 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: {
+ TQCString 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 TQIBaseResult::reset (const TQString& query)
+{
+// qDebug("reset: %s", query.ascii());
+ if (!driver() || !driver()->isOpen() || driver()->isOpenError())
+ return FALSE;
+ d->cleanup();
+ setActive(FALSE);
+ setAt(TQSql::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", TQSqlError::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", TQSqlError::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", TQSqlError::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 TQIBaseResult::gotoNext(TQtSqlCachedResult::RowCache* row)
+{
+ ISC_STATUS stat = isc_dsql_fetch(d->status, &d->stmt, 1, d->sqlda);
+
+ if (stat == 100) {
+ // no more rows
+ setAt(TQSql::AfterLast);
+ return FALSE;
+ }
+ if (d->isError("Could not fetch next item", TQSqlError::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
+ TQVariant 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] = TQString::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] = TQVariant(*(Q_LLONG*)buf);
+ break;
+ case SQL_LONG:
+ if (sizeof(int) == sizeof(long)) //dear compiler: please optimize me out.
+ (*row)[i] = TQVariant((int)(*(long*)buf));
+ else
+ (*row)[i] = TQVariant((Q_LLONG)(*(long*)buf));
+ break;
+ case SQL_SHORT:
+ (*row)[i] = TQVariant((int)(*(short*)buf));
+ break;
+ case SQL_FLOAT:
+ (*row)[i] = TQVariant((double)(*(float*)buf));
+ break;
+ case SQL_DOUBLE:
+ (*row)[i] = TQVariant(*(double*)buf);
+ break;
+ case SQL_TIMESTAMP:
+ (*row)[i] = toTQDateTime((ISC_TIMESTAMP*)buf);
+ break;
+ case SQL_TYPE_TIME:
+ (*row)[i] = toTQTime(*(ISC_TIME*)buf);
+ break;
+ case SQL_TYPE_DATE:
+ (*row)[i] = toTQDate(*(ISC_DATE*)buf);
+ break;
+ case SQL_TEXT:
+ (*row)[i] = TQString::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] = TQVariant();
+ break;
+ }
+ }
+
+ return TRUE;
+}
+
+int TQIBaseResult::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 TQIBaseResult::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", TQSqlError::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;
+}
+
+/*********************************/
+
+TQIBaseDriver::TQIBaseDriver(TQObject * parent, const char * name)
+ : TQSqlDriver(parent, name ? name : TQIBASE_DRIVER_NAME)
+{
+ d = new TQIBaseDriverPrivate(this);
+}
+
+TQIBaseDriver::TQIBaseDriver(void *connection, TQObject *parent, const char *name)
+ : TQSqlDriver(parent, name ? name : TQIBASE_DRIVER_NAME)
+{
+ d = new TQIBaseDriverPrivate(this);
+ d->ibase = (isc_db_handle)(long int)connection;
+ setOpen(TRUE);
+ setOpenError(FALSE);
+}
+
+TQIBaseDriver::~TQIBaseDriver()
+{
+ delete d;
+}
+
+bool TQIBaseDriver::hasFeature(DriverFeature f) const
+{
+ switch (f) {
+ case Transactions:
+// case QuerySize:
+ case PreparedQueries:
+ case PositionalPlaceholders:
+ case Unicode:
+ case BLOB:
+ return TRUE;
+ default:
+ return FALSE;
+ }
+}
+
+bool TQIBaseDriver::open(const TQString & db,
+ const TQString & user,
+ const TQString & password,
+ const TQString & host,
+ int /*port*/,
+ const TQString & /* connOpts */)
+{
+ if (isOpen())
+ close();
+
+ static const char enc[8] = "UTF_FSS";
+ TQCString usr = user.local8Bit();
+ TQCString pass = password.local8Bit();
+ usr.truncate(255);
+ pass.truncate(255);
+
+ TQByteArray 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;
+
+ TQString 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", TQSqlError::Connection)) {
+ setOpenError(TRUE);
+ return FALSE;
+ }
+
+ setOpen(TRUE);
+ return TRUE;
+}
+
+void TQIBaseDriver::close()
+{
+ if (isOpen()) {
+ isc_detach_database(d->status, &d->ibase);
+ d->ibase = 0;
+ setOpen(FALSE);
+ setOpenError(FALSE);
+ }
+}
+
+TQSqlQuery TQIBaseDriver::createQuery() const
+{
+ return TQSqlQuery(new TQIBaseResult(this));
+}
+
+bool TQIBaseDriver::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", TQSqlError::Transaction);
+}
+
+bool TQIBaseDriver::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", TQSqlError::Transaction);
+}
+
+bool TQIBaseDriver::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", TQSqlError::Transaction);
+}
+
+TQStringList TQIBaseDriver::tables(const TQString& typeName) const
+{
+ TQStringList res;
+ if (!isOpen())
+ return res;
+
+ int type = typeName.isEmpty() ? (int)TQSql::Tables | (int)TQSql::Views : typeName.toInt();
+ TQString typeFilter;
+
+ if (type == (int)TQSql::SystemTables) {
+ typeFilter += "RDB$SYSTEM_FLAG != 0";
+ } else if (type == ((int)TQSql::SystemTables | (int)TQSql::Views)) {
+ typeFilter += "RDB$SYSTEM_FLAG != 0 OR RDB$VIEW_BLR NOT NULL";
+ } else {
+ if (!(type & (int)TQSql::SystemTables))
+ typeFilter += "RDB$SYSTEM_FLAG = 0 AND ";
+ if (!(type & (int)TQSql::Views))
+ typeFilter += "RDB$VIEW_BLR IS NULL AND ";
+ if (!(type & (int)TQSql::Tables))
+ typeFilter += "RDB$VIEW_BLR IS NOT NULL AND ";
+ if (!typeFilter.isEmpty())
+ typeFilter.truncate(typeFilter.length() - 5);
+ }
+ if (!typeFilter.isEmpty())
+ typeFilter.prepend("where ");
+
+ TQSqlQuery 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;
+}
+
+TQSqlRecord TQIBaseDriver::record(const TQString& tablename) const
+{
+ TQSqlRecord rec;
+ if (!isOpen())
+ return rec;
+
+ TQSqlQuery 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()) {
+ TQSqlField field(q.value(0).toString().stripWhiteSpace(), qIBaseTypeName(q.value(1).toInt()));
+ rec.append(field);
+ }
+
+ return rec;
+}
+
+TQSqlRecordInfo TQIBaseDriver::recordInfo(const TQString& tablename) const
+{
+ TQSqlRecordInfo rec;
+ if (!isOpen())
+ return rec;
+
+ TQSqlQuery 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()) {
+ TQVariant::Type type = qIBaseTypeName(q.value(1).toInt());
+ TQSqlFieldInfo field(q.value(0).toString().stripWhiteSpace(), type, q.value(5).toInt(),
+ q.value(2).toInt(), q.value(4).toInt(), TQVariant());
+
+ rec.append(field);
+ }
+
+ return rec;
+}
+
+TQSqlIndex TQIBaseDriver::primaryIndex(const TQString &table) const
+{
+ TQSqlIndex index(table);
+ if (!isOpen())
+ return index;
+
+ TQSqlQuery 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()) {
+ TQSqlField 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;
+}
+
+TQSqlRecord TQIBaseDriver::record(const TQSqlQuery& query) const
+{
+ TQSqlRecord rec;
+ if (query.isActive() && query.driver() == this) {
+ TQIBaseResult* result = (TQIBaseResult*)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];
+ TQSqlField f(TQString::fromLatin1(v.sqlname, v.sqlname_length).stripWhiteSpace(),
+ qIBaseTypeName2(result->d->sqlda->sqlvar[i].sqltype));
+ rec.append(f);
+ }
+ }
+ return rec;
+}
+
+TQSqlRecordInfo TQIBaseDriver::recordInfo(const TQSqlQuery& query) const
+{
+ TQSqlRecordInfo rec;
+ if (query.isActive() && query.driver() == this) {
+ TQIBaseResult* result = (TQIBaseResult*)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];
+ TQSqlFieldInfo f(TQString::fromLatin1(v.sqlname, v.sqlname_length).stripWhiteSpace(),
+ qIBaseTypeName2(result->d->sqlda->sqlvar[i].sqltype),
+ -1, v.sqllen, TQABS(v.sqlscale), TQVariant(), v.sqltype);
+ rec.append(f);
+ }
+ }
+ return rec;
+}
+
+TQString TQIBaseDriver::formatValue(const TQSqlField* field, bool trimStrings) const
+{
+ switch (field->type()) {
+ case TQVariant::DateTime: {
+ TQDateTime datetime = field->value().toDateTime();
+ if (datetime.isValid())
+ return "'" + TQString::number(datetime.date().year()) + "-" +
+ TQString::number(datetime.date().month()) + "-" +
+ TQString::number(datetime.date().day()) + " " +
+ TQString::number(datetime.time().hour()) + ":" +
+ TQString::number(datetime.time().minute()) + ":" +
+ TQString::number(datetime.time().second()) + "." +
+ TQString::number(datetime.time().msec()).rightJustify(3, '0', TRUE) + "'";
+ else
+ return "NULL";
+ }
+ case TQVariant::Time: {
+ TQTime time = field->value().toTime();
+ if (time.isValid())
+ return "'" + TQString::number(time.hour()) + ":" +
+ TQString::number(time.minute()) + ":" +
+ TQString::number(time.second()) + "." +
+ TQString::number(time.msec()).rightJustify(3, '0', TRUE) + "'";
+ else
+ return "NULL";
+ }
+ case TQVariant::Date: {
+ TQDate date = field->value().toDate();
+ if (date.isValid())
+ return "'" + TQString::number(date.year()) + "-" +
+ TQString::number(date.month()) + "-" +
+ TQString::number(date.day()) + "'";
+ else
+ return "NULL";
+ }
+ default:
+ return TQSqlDriver::formatValue(field, trimStrings);
+ }
+}
diff --git a/src/sql/drivers/ibase/qsql_ibase.h b/src/sql/drivers/ibase/qsql_ibase.h
new file mode 100644
index 000000000..c0e8717de
--- /dev/null
+++ b/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 TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQL_IBASE_H
+#define TQSQL_IBASE_H
+
+#include "qsqlresult.h"
+#include "qsqldriver.h"
+#include "../cache/qsqlcachedresult.h"
+
+
+class TQIBaseDriverPrivate;
+class TQIBaseResultPrivate;
+class TQIBaseDriver;
+
+class TQIBaseResult : public TQtSqlCachedResult
+{
+ friend class TQIBaseDriver;
+ friend class TQIBaseResultPrivate;
+
+public:
+ TQIBaseResult(const TQIBaseDriver* db);
+ virtual ~TQIBaseResult();
+
+ bool prepare(const TQString& query);
+ bool exec();
+
+protected:
+ bool gotoNext(TQtSqlCachedResult::RowCache* row);
+ bool reset (const TQString& query);
+ int size();
+ int numRowsAffected();
+
+private:
+ TQIBaseResultPrivate* d;
+};
+
+class TQIBaseDriver : public TQSqlDriver
+{
+ friend class TQIBaseDriverPrivate;
+ friend class TQIBaseResultPrivate;
+ friend class TQIBaseResult;
+public:
+ TQIBaseDriver(TQObject *parent = 0, const char *name = 0);
+ TQIBaseDriver(void *connection, TQObject *parent = 0, const char *name = 0);
+ virtual ~TQIBaseDriver();
+ bool hasFeature(DriverFeature f) const;
+ bool open(const TQString & db,
+ const TQString & user,
+ const TQString & password,
+ const TQString & host,
+ int port,
+ const TQString & connOpts);
+ bool open( const TQString & db,
+ const TQString & user,
+ const TQString & password,
+ const TQString & host,
+ int port ) { return open (db, user, password, host, port, TQString()); }
+ void close();
+ TQSqlQuery createQuery() const;
+ bool beginTransaction();
+ bool commitTransaction();
+ bool rollbackTransaction();
+ TQStringList tables(const TQString& typeName) const;
+
+ TQSqlRecord record(const TQString& tablename) const;
+ TQSqlRecordInfo recordInfo(const TQString& tablename) const;
+ TQSqlIndex primaryIndex(const TQString &table) const;
+ TQSqlRecord record(const TQSqlQuery& query) const;
+ TQSqlRecordInfo recordInfo(const TQSqlQuery& query) const;
+
+ TQString formatValue(const TQSqlField* field, bool trimStrings) const;
+
+private:
+ TQIBaseDriverPrivate* d;
+};
+
+
+#endif
+
diff --git a/src/sql/drivers/mysql/qsql_mysql.cpp b/src/sql/drivers/mysql/qsql_mysql.cpp
new file mode 100644
index 000000000..b0afb436d
--- /dev/null
+++ b/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 TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQMYSQL_DRIVER_NAME "TQMYSQL3"
+
+#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
+
+TQPtrDict<TQSqlOpenExtension> *qSqlOpenExtDict();
+
+static int qMySqlConnectionCount = 0;
+static bool qMySqlInitHandledByUser = FALSE;
+
+class TQMYSQLOpenExtension : public TQSqlOpenExtension
+{
+public:
+ TQMYSQLOpenExtension( TQMYSQLDriver *dri )
+ : TQSqlOpenExtension(), driver(dri) {}
+ ~TQMYSQLOpenExtension() {}
+
+ bool open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts );
+
+private:
+ TQMYSQLDriver *driver;
+};
+
+bool TQMYSQLOpenExtension::open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts )
+{
+ return driver->open( db, user, password, host, port, connOpts );
+}
+
+class TQMYSQLDriverPrivate
+{
+public:
+ TQMYSQLDriverPrivate() : mysql(0) {}
+ MYSQL* mysql;
+};
+
+class TQMYSQLResultPrivate : public TQMYSQLDriverPrivate
+{
+public:
+ TQMYSQLResultPrivate() : TQMYSQLDriverPrivate(), result(0) {}
+ MYSQL_RES* result;
+ MYSQL_ROW row;
+ TQValueVector<TQVariant::Type> fieldTypes;
+};
+
+TQSqlError qMakeError( const TQString& err, int type, const TQMYSQLDriverPrivate* p )
+{
+ return TQSqlError(TQMYSQL_DRIVER_NAME ": " + err, TQString(mysql_error( p->mysql )), type, mysql_errno( p->mysql ));
+}
+
+TQVariant::Type qDecodeMYSQLType( int mysqltype, uint flags )
+{
+ TQVariant::Type type;
+ switch ( mysqltype ) {
+ case FIELD_TYPE_TINY :
+ case FIELD_TYPE_SHORT :
+ case FIELD_TYPE_LONG :
+ case FIELD_TYPE_INT24 :
+ type = (flags & UNSIGNED_FLAG) ? TQVariant::UInt : TQVariant::Int;
+ break;
+ case FIELD_TYPE_YEAR :
+ type = TQVariant::Int;
+ break;
+ case FIELD_TYPE_LONGLONG :
+ type = (flags & UNSIGNED_FLAG) ? TQVariant::ULongLong : TQVariant::LongLong;
+ break;
+ case FIELD_TYPE_DECIMAL :
+ case FIELD_TYPE_FLOAT :
+ case FIELD_TYPE_DOUBLE :
+ type = TQVariant::Double;
+ break;
+ case FIELD_TYPE_DATE :
+ type = TQVariant::Date;
+ break;
+ case FIELD_TYPE_TIME :
+ type = TQVariant::Time;
+ break;
+ case FIELD_TYPE_DATETIME :
+ case FIELD_TYPE_TIMESTAMP :
+ type = TQVariant::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) ? TQVariant::ByteArray : TQVariant::CString;
+ break;
+ default:
+ case FIELD_TYPE_ENUM :
+ case FIELD_TYPE_SET :
+ case FIELD_TYPE_STRING :
+ case FIELD_TYPE_VAR_STRING :
+ type = TQVariant::String;
+ break;
+ }
+ return type;
+}
+
+TQMYSQLResult::TQMYSQLResult( const TQMYSQLDriver* db )
+: TQSqlResult( db )
+{
+ d = new TQMYSQLResultPrivate();
+ d->mysql = db->d->mysql;
+}
+
+TQMYSQLResult::~TQMYSQLResult()
+{
+ cleanup();
+ delete d;
+}
+
+MYSQL_RES* TQMYSQLResult::result()
+{
+ return d->result;
+}
+
+void TQMYSQLResult::cleanup()
+{
+ if ( d->result ) {
+ mysql_free_result( d->result );
+ }
+ d->result = NULL;
+ d->row = NULL;
+ setAt( -1 );
+ setActive( FALSE );
+}
+
+bool TQMYSQLResult::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 TQMYSQLResult::fetchNext()
+{
+ d->row = mysql_fetch_row( d->result );
+ if ( !d->row )
+ return FALSE;
+ setAt( at() + 1 );
+ return TRUE;
+}
+
+bool TQMYSQLResult::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 TQMYSQLResult::fetchFirst()
+{
+ if ( isForwardOnly() ) // again, fake it
+ return fetchNext();
+ return fetch( 0 );
+}
+
+TQVariant TQMYSQLResult::data( int field )
+{
+ if ( !isSelect() || field >= (int) d->fieldTypes.count() ) {
+ qWarning( "TQMYSQLResult::data: column %d out of range", field );
+ return TQVariant();
+ }
+
+ TQString val( d->row[field] );
+ switch ( d->fieldTypes.at( field ) ) {
+ case TQVariant::LongLong:
+ return TQVariant( val.toLongLong() );
+ case TQVariant::ULongLong:
+ return TQVariant( val.toULongLong() );
+ case TQVariant::Int:
+ return TQVariant( val.toInt() );
+ case TQVariant::UInt:
+ return TQVariant( val.toUInt() );
+ case TQVariant::Double:
+ return TQVariant( val.toDouble() );
+ case TQVariant::Date:
+ if ( val.isEmpty() ) {
+ return TQVariant( TQDate() );
+ } else {
+ return TQVariant( TQDate::fromString( val, TQt::ISODate ) );
+ }
+ case TQVariant::Time:
+ if ( val.isEmpty() ) {
+ return TQVariant( TQTime() );
+ } else {
+ return TQVariant( TQTime::fromString( val, TQt::ISODate ) );
+ }
+ case TQVariant::DateTime:
+ if ( val.isEmpty() )
+ return TQVariant( TQDateTime() );
+ if ( val.length() == 14u )
+ // TIMESTAMPS have the format yyyyMMddhhmmss
+ val.insert(4, "-").insert(7, "-").insert(10, 'T').insert(13, ':').insert(16, ':');
+ return TQVariant( TQDateTime::fromString( val, TQt::ISODate ) );
+ case TQVariant::ByteArray: {
+ unsigned long* fl = mysql_fetch_lengths( d->result );
+ TQByteArray ba;
+ ba.duplicate( d->row[field], fl[field] );
+ return TQVariant( ba );
+ }
+ default:
+ case TQVariant::String:
+ case TQVariant::CString:
+ return TQVariant( val );
+ }
+#ifdef QT_CHECK_RANGE
+ qWarning("TQMYSQLResult::data: unknown data type");
+#endif
+ return TQVariant();
+}
+
+bool TQMYSQLResult::isNull( int field )
+{
+ if ( d->row[field] == NULL )
+ return TRUE;
+ return FALSE;
+}
+
+bool TQMYSQLResult::reset ( const TQString& 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", TQSqlError::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", TQSqlError::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] = TQVariant::String;
+ else
+ d->fieldTypes[i] = qDecodeMYSQLType( field->type, field->flags );
+ }
+ }
+ setActive( TRUE );
+ return TRUE;
+}
+
+int TQMYSQLResult::size()
+{
+ return isSelect() ? (int)mysql_num_rows( d->result ) : -1;
+}
+
+int TQMYSQLResult::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( "TQMYSQLDriver::qServerInit: unable to start server." );
+# endif
+ }
+
+# endif // MYSQL_VERSION_ID
+#endif // Q_NO_MYSQL_EMBEDDED
+}
+
+TQMYSQLDriver::TQMYSQLDriver( TQObject * parent, const char * name )
+ : TQSqlDriver( parent, name ? name : TQMYSQL_DRIVER_NAME )
+{
+ init();
+ qServerInit();
+}
+
+/*!
+ Create a driver instance with an already open connection handle.
+*/
+
+TQMYSQLDriver::TQMYSQLDriver( MYSQL * con, TQObject * parent, const char * name )
+ : TQSqlDriver( parent, name ? name : TQMYSQL_DRIVER_NAME )
+{
+ init();
+ if ( con ) {
+ d->mysql = (MYSQL *) con;
+ setOpen( TRUE );
+ setOpenError( FALSE );
+ if (qMySqlConnectionCount == 1)
+ qMySqlInitHandledByUser = TRUE;
+ } else {
+ qServerInit();
+ }
+}
+
+void TQMYSQLDriver::init()
+{
+ qSqlOpenExtDict()->insert( this, new TQMYSQLOpenExtension(this) );
+ d = new TQMYSQLDriverPrivate();
+ d->mysql = 0;
+ qMySqlConnectionCount++;
+}
+
+TQMYSQLDriver::~TQMYSQLDriver()
+{
+ qMySqlConnectionCount--;
+ if (qMySqlConnectionCount == 0 && !qMySqlInitHandledByUser)
+ qServerEnd();
+
+ delete d;
+ if ( !qSqlOpenExtDict()->isEmpty() ) {
+ TQSqlOpenExtension *ext = qSqlOpenExtDict()->take( this );
+ delete ext;
+ }
+}
+
+bool TQMYSQLDriver::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 TQMYSQLDriver::open( const TQString&,
+ const TQString&,
+ const TQString&,
+ const TQString&,
+ int )
+{
+ qWarning("TQMYSQLDriver::open(): This version of open() is no longer supported." );
+ return FALSE;
+}
+
+bool TQMYSQLDriver::open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts )
+{
+ if ( isOpen() )
+ close();
+
+ unsigned int optionFlags = 0;
+
+ TQStringList raw = TQStringList::split( ';', connOpts );
+ TQStringList opts;
+ TQStringList::ConstIterator it;
+
+ // extract the real options from the string
+ for ( it = raw.begin(); it != raw.end(); ++it ) {
+ TQString tmp( *it );
+ int idx;
+ if ( (idx = tmp.find( '=' )) != -1 ) {
+ TQString val( tmp.mid( idx + 1 ) );
+ val.simplifyWhiteSpace();
+ if ( val == "TRUE" || val == "1" )
+ opts << tmp.left( idx );
+ else
+ qWarning( "TQMYSQLDriver::open: Illegal connect option value '%s'", tmp.latin1() );
+ } else {
+ opts << tmp;
+ }
+ }
+
+ for ( it = opts.begin(); it != opts.end(); ++it ) {
+ TQString 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( "TQMYSQLDriver::open: Unknown connect option '%s'", (*it).latin1() );
+ }
+
+ if ( (d->mysql = mysql_init((MYSQL*) 0)) &&
+ mysql_real_connect( d->mysql,
+ host,
+ user,
+ password,
+ db.isNull() ? TQString("") : db,
+ (port > -1) ? port : 0,
+ NULL,
+ optionFlags ) )
+ {
+ if ( !db.isEmpty() && mysql_select_db( d->mysql, db )) {
+ setLastError( qMakeError("Unable open database '" + db + "'", TQSqlError::Connection, d ) );
+ mysql_close( d->mysql );
+ setOpenError( TRUE );
+ return FALSE;
+ }
+ } else {
+ setLastError( qMakeError( "Unable to connect", TQSqlError::Connection, d ) );
+ mysql_close( d->mysql );
+ setOpenError( TRUE );
+ return FALSE;
+ }
+ setOpen( TRUE );
+ setOpenError( FALSE );
+ return TRUE;
+}
+
+void TQMYSQLDriver::close()
+{
+ if ( isOpen() ) {
+ mysql_close( d->mysql );
+ setOpen( FALSE );
+ setOpenError( FALSE );
+ }
+}
+
+TQSqlQuery TQMYSQLDriver::createQuery() const
+{
+ return TQSqlQuery( new TQMYSQLResult( this ) );
+}
+
+TQStringList TQMYSQLDriver::tables( const TQString& typeName ) const
+{
+ TQStringList tl;
+ if ( !isOpen() )
+ return tl;
+ if ( !typeName.isEmpty() && !(typeName.toInt() & (int)TQSql::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( TQString(row[0]) );
+ i++;
+ }
+ mysql_free_result( tableRes );
+ return tl;
+}
+
+TQSqlIndex TQMYSQLDriver::primaryIndex( const TQString& tablename ) const
+{
+ TQSqlIndex idx;
+ if ( !isOpen() )
+ return idx;
+ TQSqlQuery i = createQuery();
+ TQString stmt( "show index from %1;" );
+ TQSqlRecord 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;
+}
+
+TQSqlRecord TQMYSQLDriver::record( const TQString& tablename ) const
+{
+ TQSqlRecord 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 ))) {
+ TQSqlField f ( TQString( field->name ) , qDecodeMYSQLType( (int)field->type, field->flags ) );
+ fil.append ( f );
+ }
+ mysql_free_result( r );
+ return fil;
+}
+
+TQSqlRecord TQMYSQLDriver::record( const TQSqlQuery& query ) const
+{
+ TQSqlRecord fil;
+ if ( !isOpen() )
+ return fil;
+ if ( query.isActive() && query.isSelect() && query.driver() == this ) {
+ TQMYSQLResult* result = (TQMYSQLResult*)query.result();
+ TQMYSQLResultPrivate* p = result->d;
+ if ( !mysql_errno( p->mysql ) ) {
+ for ( ;; ) {
+ MYSQL_FIELD* f = mysql_fetch_field( p->result );
+ if ( f ) {
+ TQSqlField fi( TQString((const char*)f->name), qDecodeMYSQLType( f->type, f->flags ) );
+ fil.append( fi );
+ } else
+ break;
+ }
+ }
+ mysql_field_seek( p->result, 0 );
+ }
+ return fil;
+}
+
+TQSqlRecordInfo TQMYSQLDriver::recordInfo( const TQString& tablename ) const
+{
+ TQSqlRecordInfo 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 ( TQSqlFieldInfo( TQString( field->name ),
+ qDecodeMYSQLType( (int)field->type, field->flags ),
+ IS_NOT_NULL( field->flags ),
+ (int)field->length,
+ (int)field->decimals,
+ TQString( field->def ),
+ (int)field->type ) );
+ }
+ mysql_free_result( r );
+ return info;
+}
+
+TQSqlRecordInfo TQMYSQLDriver::recordInfo( const TQSqlQuery& query ) const
+{
+ TQSqlRecordInfo info;
+ if ( !isOpen() )
+ return info;
+ if ( query.isActive() && query.isSelect() && query.driver() == this ) {
+ TQMYSQLResult* result = (TQMYSQLResult*)query.result();
+ TQMYSQLResultPrivate* p = result->d;
+ if ( !mysql_errno( p->mysql ) ) {
+ for ( ;; ) {
+ MYSQL_FIELD* field = mysql_fetch_field( p->result );
+ if ( field ) {
+ info.append ( TQSqlFieldInfo( TQString( field->name ),
+ qDecodeMYSQLType( (int)field->type, field->flags ),
+ IS_NOT_NULL( field->flags ),
+ (int)field->length,
+ (int)field->decimals,
+ TQVariant(),
+ (int)field->type ) );
+
+ } else
+ break;
+ }
+ }
+ mysql_field_seek( p->result, 0 );
+ }
+ return info;
+}
+
+MYSQL* TQMYSQLDriver::mysql()
+{
+ return d->mysql;
+}
+
+bool TQMYSQLDriver::beginTransaction()
+{
+#ifndef CLIENT_TRANSACTIONS
+ return FALSE;
+#endif
+ if ( !isOpen() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQMYSQLDriver::beginTransaction: Database not open" );
+#endif
+ return FALSE;
+ }
+ if ( mysql_query( d->mysql, "BEGIN WORK" ) ) {
+ setLastError( qMakeError("Unable to begin transaction", TQSqlError::Statement, d ) );
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool TQMYSQLDriver::commitTransaction()
+{
+#ifndef CLIENT_TRANSACTIONS
+ return FALSE;
+#endif
+ if ( !isOpen() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQMYSQLDriver::commitTransaction: Database not open" );
+#endif
+ return FALSE;
+ }
+ if ( mysql_query( d->mysql, "COMMIT" ) ) {
+ setLastError( qMakeError("Unable to commit transaction", TQSqlError::Statement, d ) );
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool TQMYSQLDriver::rollbackTransaction()
+{
+#ifndef CLIENT_TRANSACTIONS
+ return FALSE;
+#endif
+ if ( !isOpen() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQMYSQLDriver::rollbackTransaction: Database not open" );
+#endif
+ return FALSE;
+ }
+ if ( mysql_query( d->mysql, "ROLLBACK" ) ) {
+ setLastError( qMakeError("Unable to rollback transaction", TQSqlError::Statement, d ) );
+ return FALSE;
+ }
+ return TRUE;
+}
+
+TQString TQMYSQLDriver::formatValue( const TQSqlField* field, bool trimStrings ) const
+{
+ TQString r;
+ if ( field->isNull() ) {
+ r = nullText();
+ } else {
+ switch( field->type() ) {
+ case TQVariant::ByteArray: {
+
+ const TQByteArray 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 TQVariant::String:
+ case TQVariant::CString: {
+ // Escape '\' characters
+ r = TQSqlDriver::formatValue( field );
+ r.replace( "\\", "\\\\" );
+ break;
+ }
+ default:
+ r = TQSqlDriver::formatValue( field, trimStrings );
+ }
+ }
+ return r;
+}
diff --git a/src/sql/drivers/mysql/qsql_mysql.h b/src/sql/drivers/mysql/qsql_mysql.h
new file mode 100644
index 000000000..d47aa6ea9
--- /dev/null
+++ b/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 TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQL_MYSQL_H
+#define TQSQL_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 TQMYSQLDriverPrivate;
+class TQMYSQLResultPrivate;
+class TQMYSQLDriver;
+class TQSqlRecordInfo;
+
+class TQMYSQLResult : public TQSqlResult
+{
+ friend class TQMYSQLDriver;
+public:
+ TQMYSQLResult( const TQMYSQLDriver* db );
+ ~TQMYSQLResult();
+
+ MYSQL_RES* result();
+protected:
+ void cleanup();
+ bool fetch( int i );
+ bool fetchNext();
+ bool fetchLast();
+ bool fetchFirst();
+ TQVariant data( int field );
+ bool isNull( int field );
+ bool reset ( const TQString& query );
+ int size();
+ int numRowsAffected();
+private:
+ TQMYSQLResultPrivate* d;
+};
+
+class Q_EXPORT_SQLDRIVER_MYSQL TQMYSQLDriver : public TQSqlDriver
+{
+ friend class TQMYSQLResult;
+public:
+ TQMYSQLDriver( TQObject * parent=0, const char * name=0 );
+ TQMYSQLDriver( MYSQL * con, TQObject * parent=0, const char * name=0 );
+ ~TQMYSQLDriver();
+ bool hasFeature( DriverFeature f ) const;
+ bool open( const TQString & db,
+ const TQString & user = TQString::null,
+ const TQString & password = TQString::null,
+ const TQString & host = TQString::null,
+ int port = -1 );
+ void close();
+ TQSqlQuery createQuery() const;
+ TQStringList tables( const TQString& user ) const;
+ TQSqlIndex primaryIndex( const TQString& tablename ) const;
+ TQSqlRecord record( const TQString& tablename ) const;
+ TQSqlRecord record( const TQSqlQuery& query ) const;
+ TQSqlRecordInfo recordInfo( const TQString& tablename ) const;
+ TQSqlRecordInfo recordInfo( const TQSqlQuery& query ) const;
+ TQString formatValue( const TQSqlField* field,
+ bool trimStrings ) const;
+ MYSQL* mysql();
+ // ### remove me for 4.0
+ bool open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts );
+
+protected:
+ bool beginTransaction();
+ bool commitTransaction();
+ bool rollbackTransaction();
+private:
+ void init();
+ TQMYSQLDriverPrivate* d;
+};
+
+
+#endif
diff --git a/src/sql/drivers/odbc/debian_qsql_odbc.h b/src/sql/drivers/odbc/debian_qsql_odbc.h
new file mode 100644
index 000000000..4b91f475c
--- /dev/null
+++ b/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/src/sql/drivers/odbc/qsql_odbc.cpp b/src/sql/drivers/odbc/qsql_odbc.cpp
new file mode 100644
index 000000000..4d0f7969f
--- /dev/null
+++ b/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 TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLLEN SQLLEN
+#else
+# define TQSQLLEN SQLINTEGER
+#endif
+
+#ifdef SQLULEN
+# define TQSQLULEN SQLULEN
+#else
+# define TQSQLULEN SQLUINTEGER
+#endif
+
+
+static const TQSQLLEN COLNAMESIZE = 256;
+//Map TQt parameter types to ODBC types
+static const SQLSMALLINT qParamType[ 4 ] = { SQL_PARAM_INPUT, SQL_PARAM_INPUT, SQL_PARAM_OUTPUT, SQL_PARAM_INPUT_OUTPUT };
+
+class TQODBCPrivate
+{
+public:
+ TQODBCPrivate()
+ : hEnv(0), hDbc(0), hStmt(0), useSchema(FALSE)
+ {
+ sql_char_type = sql_varchar_type = sql_longvarchar_type = TQVariant::CString;
+ unicode = FALSE;
+ }
+
+ SQLHANDLE hEnv;
+ SQLHANDLE hDbc;
+ SQLHANDLE hStmt;
+
+ bool unicode;
+ bool useSchema;
+ TQVariant::Type sql_char_type;
+ TQVariant::Type sql_varchar_type;
+ TQVariant::Type sql_longvarchar_type;
+
+ TQSqlRecordInfo rInf;
+
+ bool checkDriver() const;
+ void checkUnicode();
+ void checkSchemaUsage();
+ bool setConnectionOptions( const TQString& connOpts );
+ void splitTableQualifier(const TQString &qualifier, TQString &catalog,
+ TQString &schema, TQString &table);
+};
+
+class TQODBCPreparedExtension : public TQSqlExtension
+{
+public:
+ TQODBCPreparedExtension( TQODBCResult * r )
+ : result( r ) {}
+
+ bool prepare( const TQString& query )
+ {
+ return result->prepare( query );
+ }
+
+ bool exec()
+ {
+ return result->exec();
+ }
+
+ TQODBCResult * result;
+};
+
+TQPtrDict<TQSqlOpenExtension> *qSqlOpenExtDict();
+
+class TQODBCOpenExtension : public TQSqlOpenExtension
+{
+public:
+ TQODBCOpenExtension( TQODBCDriver *dri )
+ : TQSqlOpenExtension(), driver(dri) {}
+ ~TQODBCOpenExtension() {}
+
+ bool open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts );
+private:
+ TQODBCDriver *driver;
+};
+
+bool TQODBCOpenExtension::open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts )
+{
+ return driver->open( db, user, password, host, port, connOpts );
+}
+
+static TQString 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 TQString( (const TQChar*)description_, (uint)msgLen );
+#else
+ return TQString::fromLocal8Bit( (const char*)description_ );
+#endif
+ return TQString::null;
+}
+
+static TQString qODBCWarn( const TQODBCPrivate* odbc)
+{
+ return ( qWarnODBCHandle( SQL_HANDLE_ENV, odbc->hEnv ) + " "
+ + qWarnODBCHandle( SQL_HANDLE_DBC, odbc->hDbc ) + " "
+ + qWarnODBCHandle( SQL_HANDLE_STMT, odbc->hStmt ) );
+}
+
+static void qSqlWarning( const TQString& message, const TQODBCPrivate* odbc )
+{
+#ifdef QT_CHECK_RANGE
+ qWarning( "%s\tError: %s", message.local8Bit().data(), qODBCWarn( odbc ).local8Bit().data() );
+#endif
+}
+
+static TQSqlError qMakeError( const TQString& err, int type, const TQODBCPrivate* p )
+{
+ return TQSqlError( "TQODBC3: " + err, qODBCWarn(p), type );
+}
+
+static TQVariant::Type qDecodeODBCType( SQLSMALLINT sqltype, const TQODBCPrivate* p )
+{
+ TQVariant::Type type = TQVariant::Invalid;
+ switch ( sqltype ) {
+ case SQL_DECIMAL:
+ case SQL_NUMERIC:
+ case SQL_REAL:
+ case SQL_FLOAT:
+ case SQL_DOUBLE:
+ type = TQVariant::Double;
+ break;
+ case SQL_SMALLINT:
+ case SQL_INTEGER:
+ case SQL_BIT:
+ case SQL_TINYINT:
+ type = TQVariant::Int;
+ break;
+ case SQL_BIGINT:
+ type = TQVariant::LongLong;
+ break;
+ case SQL_BINARY:
+ case SQL_VARBINARY:
+ case SQL_LONGVARBINARY:
+ type = TQVariant::ByteArray;
+ break;
+ case SQL_DATE:
+ case SQL_TYPE_DATE:
+ type = TQVariant::Date;
+ break;
+ case SQL_TIME:
+ case SQL_TYPE_TIME:
+ type = TQVariant::Time;
+ break;
+ case SQL_TIMESTAMP:
+ case SQL_TYPE_TIMESTAMP:
+ type = TQVariant::DateTime;
+ break;
+#ifndef Q_ODBC_VERSION_2
+ case SQL_WCHAR:
+ case SQL_WVARCHAR:
+ case SQL_WLONGVARCHAR:
+ type = TQVariant::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 = TQVariant::CString;
+ break;
+ }
+ return type;
+}
+
+static TQString qGetStringData( SQLHANDLE hStmt, int column, int colSize, bool& isNull, bool unicode = FALSE )
+{
+ TQString fieldVal;
+ SQLRETURN r = SQL_ERROR;
+ TQSQLLEN 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,
+ (TQSQLLEN)colSize,
+ &lengthIndicator );
+ if ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) {
+ if ( lengthIndicator == SQL_NULL_DATA || lengthIndicator == SQL_NO_TOTAL ) {
+ fieldVal = TQString::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 += TQString( (TQChar*) 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 = TQString::null;
+ break;
+ }
+ }
+ delete[] buf;
+ return fieldVal;
+}
+
+static TQByteArray qGetBinaryData( SQLHANDLE hStmt, int column, TQSQLLEN& lengthIndicator, bool& isNull )
+{
+ TQByteArray fieldVal;
+ SQLSMALLINT colNameLen;
+ SQLSMALLINT colType;
+ TQSQLULEN 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,
+ (TQSQLLEN)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 TQByteArray 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 )
+{
+ TQSQLLEN intbuf = 0;
+ isNull = FALSE;
+ TQSQLLEN lengthIndicator = 0;
+ SQLRETURN r = SQLGetData( hStmt,
+ column+1,
+ SQL_C_SLONG,
+ (SQLPOINTER)&intbuf,
+ (TQSQLLEN)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;
+ TQSQLLEN lengthIndicator = 0;
+ isNull = FALSE;
+ SQLRETURN r = SQLGetData( hStmt,
+ column+1,
+ SQL_C_DOUBLE,
+ (SQLPOINTER)&dblbuf,
+ (TQSQLLEN)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;
+ TQSQLLEN lengthIndicator = 0;
+ SQLRETURN r = SQLGetData( hStmt,
+ column+1,
+ SQL_C_SBIGINT,
+ (SQLPOINTER) &lngbuf,
+ (TQSQLLEN)0,
+ &lengthIndicator );
+ if ( ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) || lengthIndicator == SQL_NULL_DATA )
+ isNull = TRUE;
+
+ return lngbuf;
+}
+
+// creates a TQSqlFieldInfo from a valid hStmt generated
+// by SQLColumns. The hStmt has to point to a valid position.
+static TQSqlFieldInfo qMakeFieldInfo( const SQLHANDLE hStmt, const TQODBCPrivate* p )
+{
+ bool isNull;
+ TQString fname = qGetStringData( hStmt, 3, -1, isNull, p->unicode );
+ int type = qGetIntData( hStmt, 4, isNull ); // column type
+ int retquired = qGetIntData( hStmt, 10, isNull ); // nullable-flag
+ // retquired can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
+ if ( retquired == SQL_NO_NULLS ) {
+ retquired = 1;
+ } else if ( retquired == SQL_NULLABLE ) {
+ retquired = 0;
+ } else {
+ retquired = -1;
+ }
+ int size = qGetIntData( hStmt, 6, isNull ); // column size
+ int prec = qGetIntData( hStmt, 8, isNull ); // precision
+ return TQSqlFieldInfo( fname, qDecodeODBCType( type, p ), retquired, size, prec, TQVariant(), type );
+}
+
+static TQSqlFieldInfo qMakeFieldInfo( const TQODBCPrivate* p, int i )
+{
+ SQLSMALLINT colNameLen;
+ SQLSMALLINT colType;
+ TQSQLULEN colSize;
+ SQLSMALLINT colScale;
+ SQLSMALLINT nullable;
+ SQLRETURN r = SQL_ERROR;
+ SQLTCHAR colName[ COLNAMESIZE ];
+ r = SQLDescribeCol( p->hStmt,
+ i+1,
+ colName,
+ (TQSQLULEN)COLNAMESIZE,
+ &colNameLen,
+ &colType,
+ &colSize,
+ &colScale,
+ &nullable);
+
+ if ( r != SQL_SUCCESS ) {
+#ifdef QT_CHECK_RANGE
+ qSqlWarning( TQString("qMakeField: Unable to describe column %1").arg(i), p );
+#endif
+ return TQSqlFieldInfo();
+ }
+#ifdef UNICODE
+ TQString qColName( (const TQChar*)colName, (uint)colNameLen );
+#else
+ TQString qColName = TQString::fromLocal8Bit( (const char*)colName );
+#endif
+ // nullable can be SQL_NO_NULLS, SQL_NULLABLE or SQL_NULLABLE_UNKNOWN
+ int retquired = -1;
+ if ( nullable == SQL_NO_NULLS ) {
+ retquired = 1;
+ } else if ( nullable == SQL_NULLABLE ) {
+ retquired = 0;
+ }
+ TQVariant::Type type = qDecodeODBCType( colType, p );
+ return TQSqlFieldInfo( qColName,
+ type,
+ retquired,
+ (int)colSize == 0 ? -1 : (int)colSize,
+ (int)colScale == 0 ? -1 : (int)colScale,
+ TQVariant(),
+ (int)colType );
+}
+
+bool TQODBCPrivate::setConnectionOptions( const TQString& connOpts )
+{
+ // Set any connection attributes
+ TQStringList raw = TQStringList::split( ';', connOpts );
+ TQStringList opts;
+ SQLRETURN r = SQL_SUCCESS;
+ TQMap<TQString, TQString> connMap;
+ for ( TQStringList::ConstIterator it = raw.begin(); it != raw.end(); ++it ) {
+ TQString tmp( *it );
+ int idx;
+ if ( (idx = tmp.find( '=' )) != -1 )
+ connMap[ tmp.left( idx ) ] = tmp.mid( idx + 1 ).simplifyWhiteSpace();
+ else
+ qWarning( "TQODBCDriver::open: Illegal connect option value '%s'", tmp.latin1() );
+ }
+ if ( connMap.count() ) {
+ TQMap<TQString, TQString>::ConstIterator it;
+ TQString 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( TQString( "TQODBCDriver::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( TQString( "TQODBCDriver::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( TQString( "TQODBCDriver::open: Unknown option value '%1'" ).arg( *it ) );
+ break;
+ }
+ r = SQLSetConnectAttr( hDbc, SQL_ATTR_TRACE, (SQLPOINTER) v, 0 );
+ }
+#ifdef QT_CHECK_RANGE
+ else {
+ qWarning( TQString("TQODBCDriver::open: Unknown connection attribute '%1'").arg( opt ) );
+ }
+#endif
+ if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) {
+#ifdef QT_CHECK_RANGE
+ qSqlWarning( TQString("TQODBCDriver::open: Unable to set connection attribute '%1'").arg( opt ), this );
+#endif
+ return FALSE;
+ }
+ }
+ }
+ return TRUE;
+}
+
+void TQODBCPrivate::splitTableQualifier(const TQString & qualifier, TQString &catalog,
+ TQString &schema, TQString &table)
+{
+ if (!useSchema) {
+ table = qualifier;
+ return;
+ }
+ TQStringList l = TQStringList::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 ( TQStringList::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++;
+ }
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+
+TQODBCResult::TQODBCResult( const TQODBCDriver * db, TQODBCPrivate* p )
+: TQSqlResult(db)
+{
+ d = new TQODBCPrivate();
+ (*d) = (*p);
+ setExtension( new TQODBCPreparedExtension( this ) );
+}
+
+TQODBCResult::~TQODBCResult()
+{
+ if ( d->hStmt && driver()->isOpen() ) {
+ SQLRETURN r = SQLFreeHandle( SQL_HANDLE_STMT, d->hStmt );
+#ifdef QT_CHECK_RANGE
+ if ( r != SQL_SUCCESS )
+ qSqlWarning( "TQODBCDriver: Unable to free statement handle " + TQString::number(r), d );
+#endif
+ }
+
+ delete d;
+}
+
+bool TQODBCResult::reset ( const TQString& query )
+{
+ setActive( FALSE );
+ setAt( TQSql::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( "TQODBCResult::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( "TQODBCResult::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( "TQODBCResult::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
+ TQCString 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", TQSqlError::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 TQODBCResult::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( TQSql::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 TQODBCResult::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 TQODBCResult::fetchFirst()
+{
+ if ( isForwardOnly() && at() != TQSql::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 TQODBCResult::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 TQODBCResult::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 == TQSql::AfterLast )
+ return FALSE;
+ if ( i == TQSql::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;
+}
+
+TQVariant TQODBCResult::data( int field )
+{
+ if ( field >= (int) d->rInf.count() ) {
+ qWarning( "TQODBCResult::data: column %d out of range", field );
+ return TQVariant();
+ }
+ if ( fieldCache.contains( field ) )
+ return fieldCache[ field ];
+ SQLRETURN r(0);
+ TQSQLLEN lengthIndicator = 0;
+ bool isNull = FALSE;
+ int current = fieldCache.count();
+ for ( ; current < (field + 1); ++current ) {
+ const TQSqlFieldInfo info = d->rInf[ current ];
+ switch ( info.type() ) {
+ case TQVariant::LongLong:
+ fieldCache[ current ] = TQVariant( (Q_LLONG) qGetBigIntData( d->hStmt, current, isNull ) );
+ nullCache[ current ] = isNull;
+ break;
+ case TQVariant::Int:
+ fieldCache[ current ] = TQVariant( qGetIntData( d->hStmt, current, isNull ) );
+ nullCache[ current ] = isNull;
+ break;
+ case TQVariant::Date:
+ DATE_STRUCT dbuf;
+ r = SQLGetData( d->hStmt,
+ current+1,
+ SQL_C_DATE,
+ (SQLPOINTER)&dbuf,
+ (TQSQLLEN)0,
+ &lengthIndicator );
+ if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != SQL_NULL_DATA ) ) {
+ fieldCache[ current ] = TQVariant( TQDate( dbuf.year, dbuf.month, dbuf.day ) );
+ nullCache[ current ] = FALSE;
+ } else {
+ fieldCache[ current ] = TQVariant( TQDate() );
+ nullCache[ current ] = TRUE;
+ }
+ break;
+ case TQVariant::Time:
+ TIME_STRUCT tbuf;
+ r = SQLGetData( d->hStmt,
+ current+1,
+ SQL_C_TIME,
+ (SQLPOINTER)&tbuf,
+ (TQSQLLEN)0,
+ &lengthIndicator );
+ if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != SQL_NULL_DATA ) ) {
+ fieldCache[ current ] = TQVariant( TQTime( tbuf.hour, tbuf.minute, tbuf.second ) );
+ nullCache[ current ] = FALSE;
+ } else {
+ fieldCache[ current ] = TQVariant( TQTime() );
+ nullCache[ current ] = TRUE;
+ }
+ break;
+ case TQVariant::DateTime:
+ TIMESTAMP_STRUCT dtbuf;
+ r = SQLGetData( d->hStmt,
+ current+1,
+ SQL_C_TIMESTAMP,
+ (SQLPOINTER)&dtbuf,
+ (TQSQLLEN)0,
+ &lengthIndicator );
+ if ( ( r == SQL_SUCCESS || r == SQL_SUCCESS_WITH_INFO ) && ( lengthIndicator != SQL_NULL_DATA ) ) {
+ fieldCache[ current ] = TQVariant( TQDateTime( TQDate( dtbuf.year, dtbuf.month, dtbuf.day ), TQTime( dtbuf.hour, dtbuf.minute, dtbuf.second, dtbuf.fraction / 1000000 ) ) );
+ nullCache[ current ] = FALSE;
+ } else {
+ fieldCache[ current ] = TQVariant( TQDateTime() );
+ nullCache[ current ] = TRUE;
+ }
+ break;
+ case TQVariant::ByteArray: {
+ isNull = FALSE;
+ TQByteArray val = qGetBinaryData( d->hStmt, current, lengthIndicator, isNull );
+ fieldCache[ current ] = TQVariant( val );
+ nullCache[ current ] = isNull;
+ break; }
+ case TQVariant::String:
+ isNull = FALSE;
+ fieldCache[ current ] = TQVariant( qGetStringData( d->hStmt, current,
+ info.length(), isNull, TRUE ) );
+ nullCache[ current ] = isNull;
+ break;
+ case TQVariant::Double:
+ if ( info.typeID() == SQL_DECIMAL || info.typeID() == SQL_NUMERIC )
+ // bind Double values as string to prevent loss of precision
+ fieldCache[ current ] = TQVariant( qGetStringData( d->hStmt, current,
+ info.length() + 1, isNull, FALSE ) ); // length + 1 for the comma
+ else
+ fieldCache[ current ] = TQVariant( qGetDoubleData( d->hStmt, current, isNull ) );
+ nullCache[ current ] = isNull;
+ break;
+ case TQVariant::CString:
+ default:
+ isNull = FALSE;
+ fieldCache[ current ] = TQVariant( qGetStringData( d->hStmt, current,
+ info.length(), isNull, FALSE ) );
+ nullCache[ current ] = isNull;
+ break;
+ }
+ }
+ return fieldCache[ --current ];
+}
+
+bool TQODBCResult::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 TQODBCResult::size()
+{
+ return -1;
+}
+
+int TQODBCResult::numRowsAffected()
+{
+ TQSQLLEN affectedRowCount(0);
+ SQLRETURN r = SQLRowCount( d->hStmt, &affectedRowCount );
+ if ( r == SQL_SUCCESS )
+ return affectedRowCount;
+#ifdef QT_CHECK_RANGE
+ else
+ qSqlWarning( "TQODBCResult::numRowsAffected: Unable to count affected rows", d );
+#endif
+ return -1;
+}
+
+bool TQODBCResult::prepare( const TQString& query )
+{
+ setActive( FALSE );
+ setAt( TQSql::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( "TQODBCResult::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( "TQODBCResult::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( "TQODBCResult::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
+ TQCString query8 = query.local8Bit();
+ r = SQLPrepare( d->hStmt,
+ (SQLCHAR*) query8.data(),
+ (SQLINTEGER) query8.length() );
+#endif
+
+ if ( r != SQL_SUCCESS ) {
+#ifdef QT_CHECK_RANGE
+ qSqlWarning( "TQODBCResult::prepare: Unable to prepare statement", d );
+#endif
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool TQODBCResult::exec()
+{
+ SQLRETURN r;
+ TQPtrList<TQVirtualDestructor> tmpStorage; // holds temporary ptrs. which will be deleted on fu exit
+ tmpStorage.setAutoDelete( TRUE );
+
+ setActive( FALSE );
+ setAt( TQSql::BeforeFirst );
+ d->rInf.clear();
+
+ if ( !d->hStmt ) {
+#ifdef QT_CHECK_RANGE
+ qSqlWarning( "TQODBCResult::exec: No statement handle available", d );
+#endif
+ return FALSE;
+ } else {
+ r = SQLFreeStmt( d->hStmt, SQL_CLOSE );
+ if ( r != SQL_SUCCESS ) {
+ qSqlWarning( "TQODBCResult::exec: Unable to close statement handle", d );
+ return FALSE;
+ }
+ }
+
+ // bind parameters - only positional binding allowed
+ if ( extension()->index.count() > 0 ) {
+ TQMap<int, TQString>::Iterator it;
+ int para = 1;
+ TQVariant val;
+ for ( it = extension()->index.begin(); it != extension()->index.end(); ++it ) {
+ val = extension()->values[ it.data() ].value;
+ TQSQLLEN *ind = new TQSQLLEN( SQL_NTS );
+ tmpStorage.append( qAutoDeleter(ind) );
+ if ( val.isNull() ) {
+ *ind = SQL_NULL_DATA;
+ }
+ switch ( val.type() ) {
+ case TQVariant::Date: {
+ DATE_STRUCT * dt = new DATE_STRUCT;
+ tmpStorage.append( qAutoDeleter(dt) );
+ TQDate 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,
+ (TQSQLLEN)0,
+ *ind == SQL_NULL_DATA ? ind : NULL );
+ break; }
+ case TQVariant::Time: {
+ TIME_STRUCT * dt = new TIME_STRUCT;
+ tmpStorage.append( qAutoDeleter(dt) );
+ TQTime 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,
+ (TQSQLLEN)0,
+ *ind == SQL_NULL_DATA ? ind : NULL );
+ break; }
+ case TQVariant::DateTime: {
+ TIMESTAMP_STRUCT * dt = new TIMESTAMP_STRUCT;
+ tmpStorage.append( qAutoDeleter(dt) );
+ TQDateTime 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,
+ (TQSQLLEN)0,
+ *ind == SQL_NULL_DATA ? ind : NULL );
+ break; }
+ case TQVariant::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,
+ (TQSQLLEN)0,
+ *ind == SQL_NULL_DATA ? ind : NULL );
+ break; }
+ case TQVariant::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,
+ (TQSQLLEN)0,
+ *ind == SQL_NULL_DATA ? ind : NULL );
+ break; }
+ case TQVariant::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(),
+ (TQSQLLEN)val.asByteArray().size(),
+ ind );
+ break; }
+#ifndef Q_ODBC_VERSION_2
+ case TQVariant::String:
+ if ( d->unicode ) {
+ TQString * str = new TQString( 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(),
+ (TQSQLLEN) len,
+ ind );
+ break;
+ }
+#endif
+ // fall through
+ default: {
+ TQCString * str = new TQCString( 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(),
+ (TQSQLLEN)(str->length() + 1),
+ ind );
+ break; }
+ }
+ para++;
+ if ( r != SQL_SUCCESS ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQODBCResult::exec: unable to bind variable: %s", qODBCWarn( d ).local8Bit().data() );
+#endif
+ setLastError( qMakeError( "Unable to bind variable", TQSqlError::Statement, d ) );
+ return FALSE;
+ }
+ }
+ }
+ r = SQLExecute( d->hStmt );
+ if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQODBCResult::exec: Unable to execute statement: %s", qODBCWarn( d ).local8Bit().data() );
+#endif
+ setLastError( qMakeError( "Unable to execute statement", TQSqlError::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 ) {
+ TQMap<int, TQString>::Iterator it;
+ for ( it = extension()->index.begin(); it != extension()->index.end(); ++it ) {
+
+ SQLINTEGER* indPtr = qAutoDeleterData( (TQAutoDeleter<SQLINTEGER>*)tmpStorage.getFirst() );
+ if ( !indPtr )
+ return FALSE;
+ bool isNull = (*indPtr == SQL_NULL_DATA);
+ tmpStorage.removeFirst();
+
+ TQVariant::Type type = extension()->values[ it.data() ].value.type();
+ if ( isNull ) {
+ TQVariant v;
+ v.cast(type);
+ extension()->values[ it.data() ].value = v;
+ if (type != TQVariant::ByteArray)
+ tmpStorage.removeFirst();
+ continue;
+ }
+
+ switch (type) {
+ case TQVariant::Date: {
+ DATE_STRUCT * ds = qAutoDeleterData( (TQAutoDeleter<DATE_STRUCT>*)tmpStorage.getFirst() );
+ extension()->values[ it.data() ].value = TQVariant( TQDate( ds->year, ds->month, ds->day ) );
+ break; }
+ case TQVariant::Time: {
+ TIME_STRUCT * dt = qAutoDeleterData( (TQAutoDeleter<TIME_STRUCT>*)tmpStorage.getFirst() );
+ extension()->values[ it.data() ].value = TQVariant( TQTime( dt->hour, dt->minute, dt->second ) );
+ break; }
+ case TQVariant::DateTime: {
+ TIMESTAMP_STRUCT * dt = qAutoDeleterData( (TQAutoDeleter<TIMESTAMP_STRUCT>*)tmpStorage.getFirst() );
+ extension()->values[ it.data() ].value = TQVariant( TQDateTime( TQDate( dt->year, dt->month, dt->day ),
+ TQTime( dt->hour, dt->minute, dt->second ) ) );
+ break; }
+ case TQVariant::Int: {
+ int * v = qAutoDeleterData( (TQAutoDeleter<int>*)tmpStorage.getFirst() );
+ extension()->values[ it.data() ].value = TQVariant( *v );
+ break; }
+ case TQVariant::Double: {
+ double * v = qAutoDeleterData( (TQAutoDeleter<double>*)tmpStorage.getFirst() );
+ extension()->values[ it.data() ].value = TQVariant( *v );
+ break; }
+ case TQVariant::ByteArray:
+ break;
+ case TQVariant::String:
+ if ( d->unicode ) {
+ TQString * str = qAutoDeleterData( (TQAutoDeleter<TQString>*)tmpStorage.getFirst() );
+ extension()->values[ it.data() ].value = TQVariant( *str );
+ break;
+ }
+ // fall through
+ default: {
+ TQCString * str = qAutoDeleterData( (TQAutoDeleter<TQCString>*)tmpStorage.getFirst() );
+ extension()->values[ it.data() ].value = TQVariant( *str );
+ break; }
+ }
+ if (type != TQVariant::ByteArray)
+ tmpStorage.removeFirst();
+ }
+ }
+
+ return TRUE;
+}
+
+////////////////////////////////////////
+
+
+TQODBCDriver::TQODBCDriver( TQObject * parent, const char * name )
+ : TQSqlDriver(parent,name ? name : "TQODBC")
+{
+ init();
+}
+
+TQODBCDriver::TQODBCDriver( SQLHANDLE env, SQLHANDLE con, TQObject * parent, const char * name )
+ : TQSqlDriver(parent,name ? name : "TQODBC")
+{
+ init();
+ d->hEnv = env;
+ d->hDbc = con;
+ if ( env && con ) {
+ setOpen( TRUE );
+ setOpenError( FALSE );
+ }
+}
+
+void TQODBCDriver::init()
+{
+ qSqlOpenExtDict()->insert( this, new TQODBCOpenExtension(this) );
+ d = new TQODBCPrivate();
+}
+
+TQODBCDriver::~TQODBCDriver()
+{
+ cleanup();
+ delete d;
+ if ( !qSqlOpenExtDict()->isEmpty() ) {
+ TQSqlOpenExtension *ext = qSqlOpenExtDict()->take( this );
+ delete ext;
+ }
+}
+
+bool TQODBCDriver::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 TQODBCDriver::open( const TQString&,
+ const TQString&,
+ const TQString&,
+ const TQString&,
+ int )
+{
+ qWarning("TQODBCDriver::open(): This version of open() is no longer supported." );
+ return FALSE;
+}
+
+bool TQODBCDriver::open( const TQString & db,
+ const TQString & user,
+ const TQString & password,
+ const TQString &,
+ int,
+ const TQString& 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( "TQODBCDriver::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( "TQODBCDriver::open: Unable to allocate connection", d );
+#endif
+ setOpenError( TRUE );
+ return FALSE;
+ }
+
+ if ( !d->setConnectionOptions( connOpts ) )
+ return FALSE;
+
+ // Create the connection string
+ TQString connTQStr;
+ // support the "DRIVER={SQL SERVER};SERVER=blah" syntax
+ if ( db.contains(".dsn") )
+ connTQStr = "FILEDSN=" + db;
+ else if ( db.contains( "DRIVER" ) || db.contains( "SERVER" ) )
+ connTQStr = db;
+ else
+ connTQStr = "DSN=" + db;
+ connTQStr += ";UID=" + user + ";PWD=" + password;
+ SQLSMALLINT cb;
+ SQLTCHAR connOut[1024];
+ r = SQLDriverConnect( d->hDbc,
+ NULL,
+#ifdef UNICODE
+ (SQLWCHAR*)connTQStr.unicode(),
+#else
+ (SQLCHAR*)connTQStr.latin1(),
+#endif
+ (SQLSMALLINT)connTQStr.length(),
+ connOut,
+ 1024,
+ &cb,
+ SQL_DRIVER_NOPROMPT );
+ if ( r != SQL_SUCCESS && r != SQL_SUCCESS_WITH_INFO ) {
+ setLastError( qMakeError( "Unable to connect", TQSqlError::Connection, d ) );
+ setOpenError( TRUE );
+ return FALSE;
+ }
+
+ if ( !d->checkDriver() ) {
+ setLastError( qMakeError( "Unable to connect - Driver doesn't support all needed functionality", TQSqlError::Connection, d ) );
+ setOpenError( TRUE );
+ return FALSE;
+ }
+
+ d->checkUnicode();
+ d->checkSchemaUsage();
+
+ setOpen( TRUE );
+ setOpenError( FALSE );
+ return TRUE;
+}
+
+void TQODBCDriver::close()
+{
+ cleanup();
+ setOpen( FALSE );
+ setOpenError( FALSE );
+}
+
+void TQODBCDriver::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( "TQODBCDriver::disconnect: Unable to disconnect datasource", d );
+#endif
+ }
+
+ r = SQLFreeHandle( SQL_HANDLE_DBC, d->hDbc );
+#ifdef QT_CHECK_RANGE
+ if ( r != SQL_SUCCESS )
+ qSqlWarning( "TQODBCDriver::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( "TQODBCDriver::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 TQODBCPrivate::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 = TQVariant::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 = TQVariant::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 = TQVariant::String;
+ unicode = TRUE;
+ }
+}
+
+bool TQODBCPrivate::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 retquired functions
+ for ( i = 0; reqFunc[ i ] != 0; ++i ) {
+
+ r = SQLGetFunctions( hDbc, reqFunc[ i ], &sup );
+
+#ifdef QT_CHECK_RANGE
+ if ( r != SQL_SUCCESS ) {
+ qSqlWarning( "TQODBCDriver::checkDriver: Cannot get list of supported functions", this );
+ return FALSE;
+ }
+#endif
+ if ( sup == SQL_FALSE ) {
+#ifdef QT_CHECK_RANGE
+ qWarning ( "TQODBCDriver::open: Warning - Driver doesn't support all needed functionality (%d). "
+ "Please look at the TQt 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( "TQODBCDriver::checkDriver: Cannot get list of supported functions", this );
+ return FALSE;
+ }
+#endif
+ if ( sup == SQL_FALSE ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQODBCDriver::checkDriver: Warning - Driver doesn't support some non-critical functions (%d)", optFunc[ i ] );
+#endif
+ return TRUE;
+ }
+ }
+#endif //ODBC_CHECK_DRIVER
+
+ return TRUE;
+}
+
+void TQODBCPrivate::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);
+}
+
+TQSqlQuery TQODBCDriver::createQuery() const
+{
+ return TQSqlQuery( new TQODBCResult( this, d ) );
+}
+
+bool TQODBCDriver::beginTransaction()
+{
+ if ( !isOpen() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning(" TQODBCDriver::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", TQSqlError::Transaction, d ) );
+ return FALSE;
+ }
+ return TRUE;
+}
+
+bool TQODBCDriver::commitTransaction()
+{
+ if ( !isOpen() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning(" TQODBCDriver::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", TQSqlError::Transaction, d ) );
+ return FALSE;
+ }
+ return endTrans();
+}
+
+bool TQODBCDriver::rollbackTransaction()
+{
+ if ( !isOpen() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning(" TQODBCDriver::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", TQSqlError::Transaction, d ) );
+ return FALSE;
+ }
+ return endTrans();
+}
+
+bool TQODBCDriver::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", TQSqlError::Transaction, d ) );
+ return FALSE;
+ }
+ return TRUE;
+}
+
+TQStringList TQODBCDriver::tables( const TQString& typeName ) const
+{
+ TQStringList 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( "TQODBCDriver::tables: Unable to allocate handle", d );
+#endif
+ return tl;
+ }
+ r = SQLSetStmtAttr( hStmt,
+ SQL_ATTR_CURSOR_TYPE,
+ (SQLPOINTER)SQL_CURSOR_FORWARD_ONLY,
+ SQL_IS_UINTEGER );
+ TQString tableType;
+ if ( typeName.isEmpty() || ((type & (int)TQSql::Tables) == (int)TQSql::Tables) )
+ tableType += "TABLE,";
+ if ( (type & (int)TQSql::Views) == (int)TQSql::Views )
+ tableType += "VIEW,";
+ if ( (type & (int)TQSql::SystemTables) == (int)TQSql::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( "TQODBCDriver::tables Unable to execute table list", d );
+#endif
+ r = SQLFetchScroll( hStmt,
+ SQL_FETCH_NEXT,
+ 0);
+ while ( r == SQL_SUCCESS ) {
+ bool isNull;
+ TQString 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( "TQODBCDriver: Unable to free statement handle" + TQString::number(r), d );
+ return tl;
+}
+
+TQSqlIndex TQODBCDriver::primaryIndex( const TQString& tablename ) const
+{
+ TQSqlIndex index( tablename );
+ if ( !isOpen() )
+ return index;
+ bool usingSpecialColumns = FALSE;
+ TQSqlRecord rec = record( tablename );
+
+ SQLHANDLE hStmt;
+ SQLRETURN r = SQLAllocHandle( SQL_HANDLE_STMT,
+ d->hDbc,
+ &hStmt );
+ if ( r != SQL_SUCCESS ) {
+#ifdef QT_CHECK_RANGE
+ qSqlWarning( "TQODBCDriver::primaryIndex: Unable to list primary key", d );
+#endif
+ return index;
+ }
+ TQString 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( "TQODBCDriver::primaryIndex: Unable to execute primary key list", d );
+#endif
+ } else {
+ usingSpecialColumns = TRUE;
+ }
+ }
+ r = SQLFetchScroll( hStmt,
+ SQL_FETCH_NEXT,
+ 0 );
+ bool isNull;
+ int fakeId = 0;
+ TQString 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 = TQString::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
+ }
+ TQSqlField *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( "TQODBCDriver: Unable to free statement handle" + TQString::number(r), d );
+ return index;
+}
+
+TQSqlRecord TQODBCDriver::record( const TQString& tablename ) const
+{
+ return recordInfo( tablename ).toRecord();
+}
+
+TQSqlRecord TQODBCDriver::record( const TQSqlQuery& query ) const
+{
+ return recordInfo( query ).toRecord();
+}
+
+TQSqlRecordInfo TQODBCDriver::recordInfo( const TQString& tablename ) const
+{
+ TQSqlRecordInfo fil;
+ if ( !isOpen() )
+ return fil;
+
+ SQLHANDLE hStmt;
+ TQString 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( "TQODBCDriver::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( "TQODBCDriver::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( "TQODBCDriver: Unable to free statement handle " + TQString::number(r), d );
+
+ return fil;
+}
+
+TQSqlRecordInfo TQODBCDriver::recordInfo( const TQSqlQuery& query ) const
+{
+ TQSqlRecordInfo fil;
+ if ( !isOpen() )
+ return fil;
+ if ( query.isActive() && query.driver() == this ) {
+ TQODBCResult* result = (TQODBCResult*)query.result();
+ fil = result->d->rInf;
+ }
+ return fil;
+}
+
+SQLHANDLE TQODBCDriver::environment()
+{
+ return d->hEnv;
+}
+
+SQLHANDLE TQODBCDriver::connection()
+{
+ return d->hDbc;
+}
+
+TQString TQODBCDriver::formatValue( const TQSqlField* field,
+ bool trimStrings ) const
+{
+ TQString r;
+ if ( field->isNull() ) {
+ r = nullText();
+ } else if ( field->type() == TQVariant::DateTime ) {
+ // Use an escape sequence for the datetime fields
+ if ( field->value().toDateTime().isValid() ){
+ TQDate dt = field->value().toDateTime().date();
+ TQTime 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 '" +
+ TQString::number(dt.year()) + "-" +
+ TQString::number(dt.month()).rightJustify( 2, '0', TRUE ) + "-" +
+ TQString::number(dt.day()).rightJustify( 2, '0', TRUE ) + " " +
+ tm.toString() +
+ "' }";
+ } else
+ r = nullText();
+ } else if ( field->type() == TQVariant::ByteArray ) {
+ TQByteArray ba = field->value().toByteArray();
+ TQString 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 = TQSqlDriver::formatValue( field, trimStrings );
+ }
+ return r;
+}
diff --git a/src/sql/drivers/odbc/qsql_odbc.h b/src/sql/drivers/odbc/qsql_odbc.h
new file mode 100644
index 000000000..b65acf6ca
--- /dev/null
+++ b/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 TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQL_ODBC_H
+#define TQSQL_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 TQODBCPrivate;
+class TQODBCDriver;
+class TQSqlRecordInfo;
+
+class TQODBCResult : public TQSqlResult
+{
+ friend class TQODBCDriver;
+public:
+ TQODBCResult( const TQODBCDriver * db, TQODBCPrivate* p );
+ ~TQODBCResult();
+
+ SQLHANDLE statement();
+ bool prepare( const TQString& query );
+ bool exec();
+
+protected:
+ bool fetchNext();
+ bool fetchFirst();
+ bool fetchLast();
+ bool fetchPrior();
+ bool fetch(int i);
+ bool reset ( const TQString& query );
+ TQVariant data( int field );
+ bool isNull( int field );
+ int size();
+ int numRowsAffected();
+private:
+ TQODBCPrivate* d;
+ typedef TQMap<int,TQVariant> FieldCache;
+ FieldCache fieldCache;
+ typedef TQMap<int,bool> NullCache;
+ NullCache nullCache;
+};
+
+class Q_EXPORT_SQLDRIVER_ODBC TQODBCDriver : public TQSqlDriver
+{
+public:
+ TQODBCDriver( TQObject * parent=0, const char * name=0 );
+ TQODBCDriver( SQLHANDLE env, SQLHANDLE con, TQObject * parent=0, const char * name=0 );
+ ~TQODBCDriver();
+ bool hasFeature( DriverFeature f ) const;
+ bool open( const TQString & db,
+ const TQString & user = TQString::null,
+ const TQString & password = TQString::null,
+ const TQString & host = TQString::null,
+ int port = -1 );
+ void close();
+ TQSqlQuery createQuery() const;
+ TQStringList tables( const TQString& user ) const;
+ TQSqlRecord record( const TQString& tablename ) const;
+ TQSqlRecord record( const TQSqlQuery& query ) const;
+ TQSqlRecordInfo recordInfo( const TQString& tablename ) const;
+ TQSqlRecordInfo recordInfo( const TQSqlQuery& query ) const;
+ TQSqlIndex primaryIndex( const TQString& tablename ) const;
+ SQLHANDLE environment();
+ SQLHANDLE connection();
+
+ TQString formatValue( const TQSqlField* field,
+ bool trimStrings ) const;
+ // ### remove me for 4.0
+ bool open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts );
+
+protected:
+ bool beginTransaction();
+ bool commitTransaction();
+ bool rollbackTransaction();
+private:
+ void init();
+ bool endTrans();
+ void cleanup();
+ TQODBCPrivate* d;
+};
+
+#endif
diff --git a/src/sql/drivers/psql/qsql_psql.cpp b/src/sql/drivers/psql/qsql_psql.cpp
new file mode 100644
index 000000000..99df0fdfb
--- /dev/null
+++ b/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 TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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
+
+TQPtrDict<TQSqlDriverExtension> *qSqlDriverExtDict();
+TQPtrDict<TQSqlOpenExtension> *qSqlOpenExtDict();
+
+class TQPSQLPrivate
+{
+public:
+ TQPSQLPrivate():connection(0), result(0), isUtf8(FALSE) {}
+ PGconn *connection;
+ PGresult *result;
+ bool isUtf8;
+};
+
+class TQPSQLDriverExtension : public TQSqlDriverExtension
+{
+public:
+ TQPSQLDriverExtension( TQPSQLDriver *dri )
+ : TQSqlDriverExtension(), driver(dri) { }
+ ~TQPSQLDriverExtension() {}
+
+ bool isOpen() const;
+private:
+ TQPSQLDriver *driver;
+};
+
+bool TQPSQLDriverExtension::isOpen() const
+{
+ return PQstatus( driver->connection() ) == CONNECTION_OK;
+}
+
+class TQPSQLOpenExtension : public TQSqlOpenExtension
+{
+public:
+ TQPSQLOpenExtension( TQPSQLDriver *dri )
+ : TQSqlOpenExtension(), driver(dri) { }
+ ~TQPSQLOpenExtension() {}
+
+ bool open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts );
+private:
+ TQPSQLDriver *driver;
+};
+
+bool TQPSQLOpenExtension::open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts )
+{
+ return driver->open( db, user, password, host, port, connOpts );
+}
+
+static TQSqlError qMakeError( const TQString& err, int type, const TQPSQLPrivate* p )
+{
+ const char *s = PQerrorMessage(p->connection);
+ TQString msg = p->isUtf8 ? TQString::fromUtf8(s) : TQString::fromLocal8Bit(s);
+ return TQSqlError("TQPSQL: " + err, msg, type);
+}
+
+static TQVariant::Type qDecodePSQLType( int t )
+{
+ TQVariant::Type type = TQVariant::Invalid;
+ switch ( t ) {
+ case BOOLOID :
+ type = TQVariant::Bool;
+ break;
+ case INT8OID :
+ type = TQVariant::LongLong;
+ break;
+ case INT2OID :
+ // case INT2VECTOROID : // 7.x
+ case INT4OID :
+ type = TQVariant::Int;
+ break;
+ case NUMERICOID :
+ case FLOAT4OID :
+ case FLOAT8OID :
+ type = TQVariant::Double;
+ break;
+ case ABSTIMEOID :
+ case RELTIMEOID :
+ case DATEOID :
+ type = TQVariant::Date;
+ break;
+ case TIMEOID :
+#ifdef TIMETZOID // 7.x
+ case TIMETZOID :
+#endif
+ type = TQVariant::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 = TQVariant::DateTime;
+ break;
+ // case ZPBITOID : // 7.x
+ // case VARBITOID : // 7.x
+ case OIDOID :
+ case BYTEAOID :
+ type = TQVariant::ByteArray;
+ break;
+ case REGPROCOID :
+ case TIDOID :
+ case XIDOID :
+ case CIDOID :
+ // case OIDVECTOROID : // 7.x
+ case UNKNOWNOID :
+ // case TINTERVALOID : // 7.x
+ type = TQVariant::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 = TQVariant::String;
+ break;
+ }
+ return type;
+}
+
+TQPSQLResult::TQPSQLResult( const TQPSQLDriver* db, const TQPSQLPrivate* p )
+: TQSqlResult( db ),
+ currentSize( 0 )
+{
+ d = new TQPSQLPrivate();
+ (*d) = (*p);
+}
+
+TQPSQLResult::~TQPSQLResult()
+{
+ cleanup();
+ delete d;
+}
+
+PGresult* TQPSQLResult::result()
+{
+ return d->result;
+}
+
+void TQPSQLResult::cleanup()
+{
+ if ( d->result )
+ PQclear( d->result );
+ d->result = 0;
+ setAt( -1 );
+ currentSize = 0;
+ setActive( FALSE );
+}
+
+bool TQPSQLResult::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 TQPSQLResult::fetchFirst()
+{
+ return fetch( 0 );
+}
+
+bool TQPSQLResult::fetchLast()
+{
+ return fetch( PQntuples( d->result ) - 1 );
+}
+
+// some Postgres conversions
+static TQPoint pointFromString( const TQString& 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 TQPoint( x, y ) ;
+ } else
+ return TQPoint();
+}
+
+TQVariant TQPSQLResult::data( int i )
+{
+ if ( i >= PQnfields( d->result ) ) {
+ qWarning( "TQPSQLResult::data: column %d out of range", i );
+ return TQVariant();
+ }
+ int ptype = PQftype( d->result, i );
+ TQVariant::Type type = qDecodePSQLType( ptype );
+ const TQString val = ( d->isUtf8 && ptype != BYTEAOID ) ?
+ TQString::fromUtf8( PQgetvalue( d->result, at(), i ) ) :
+ TQString::fromLocal8Bit( PQgetvalue( d->result, at(), i ) );
+ if ( PQgetisnull( d->result, at(), i ) ) {
+ TQVariant v;
+ v.cast( type );
+ return v;
+ }
+ switch ( type ) {
+ case TQVariant::Bool:
+ {
+ TQVariant b ( (bool)(val == "t"), 0 );
+ return ( b );
+ }
+ case TQVariant::String:
+ return TQVariant( val );
+ case TQVariant::LongLong:
+ if ( val[0] == '-' )
+ return TQVariant( val.toLongLong() );
+ else
+ return TQVariant( val.toULongLong() );
+ case TQVariant::Int:
+ return TQVariant( val.toInt() );
+ case TQVariant::Double:
+ if ( ptype == NUMERICOID )
+ return TQVariant( val );
+ return TQVariant( val.toDouble() );
+ case TQVariant::Date:
+ if ( val.isEmpty() ) {
+ return TQVariant( TQDate() );
+ } else {
+ return TQVariant( TQDate::fromString( val, TQt::ISODate ) );
+ }
+ case TQVariant::Time:
+ if ( val.isEmpty() )
+ return TQVariant( TQTime() );
+ if ( val.at( val.length() - 3 ) == '+' )
+ // strip the timezone
+ return TQVariant( TQTime::fromString( val.left( val.length() - 3 ), TQt::ISODate ) );
+ return TQVariant( TQTime::fromString( val, TQt::ISODate ) );
+ case TQVariant::DateTime: {
+ if ( val.length() < 10 )
+ return TQVariant( TQDateTime() );
+ // remove the timezone
+ TQString 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 TQVariant( TQDateTime() );
+ else
+ return TQVariant( TQDateTime::fromString( dtval, TQt::ISODate ) );
+ }
+ case TQVariant::Point:
+ return TQVariant( pointFromString( val ) );
+ case TQVariant::Rect: // format '(x,y),(x',y')'
+ {
+ int pivot = val.find( "),(" );
+ if ( pivot != -1 )
+ return TQVariant( TQRect( pointFromString( val.mid(pivot+2,val.length()) ), pointFromString( val.mid(0,pivot+1) ) ) );
+ return TQVariant( TQRect() );
+ }
+ case TQVariant::PointArray: // format '((x,y),(x1,y1),...,(xn,yn))'
+ {
+ TQRegExp pointPattern("\\([0-9-]*,[0-9-]*\\)");
+ int points = val.contains( pointPattern );
+ TQPointArray 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, TQPoint() );
+ } else {
+ parray.setPoint( i, TQPoint() );
+ break;
+ }
+ idx = end+2;
+ }
+ return TQVariant( parray );
+ }
+ case TQVariant::ByteArray: {
+ if ( ptype == BYTEAOID ) {
+ uint i = 0;
+ int index = 0;
+ uint len = val.length();
+ static const TQChar backslash( '\\' );
+ TQByteArray 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 TQVariant( ba );
+ }
+
+ TQByteArray ba;
+ ((TQSqlDriver*)driver())->beginTransaction();
+ Oid oid = val.toInt();
+ int fd = lo_open( d->connection, oid, INV_READ );
+#ifdef QT_CHECK_RANGE
+ if ( fd < 0) {
+ qWarning( "TQPSQLResult::data: unable to open large object for read" );
+ ((TQSqlDriver*)driver())->commitTransaction();
+ return TQVariant( 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 );
+ ((TQSqlDriver*)driver())->commitTransaction();
+ return TQVariant( 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( "TQPSQLResult::data: unable to read large object" );
+ } else {
+ ba.duplicate( buf, size );
+ }
+ delete [] buf;
+ lo_close( d->connection, fd );
+ ((TQSqlDriver*)driver())->commitTransaction();
+ return TQVariant( ba );
+ }
+ default:
+ case TQVariant::Invalid:
+#ifdef QT_CHECK_RANGE
+ qWarning("TQPSQLResult::data: unknown data type");
+#endif
+ ;
+ }
+ return TQVariant();
+}
+
+bool TQPSQLResult::isNull( int field )
+{
+ PQgetvalue( d->result, at(), field );
+ return PQgetisnull( d->result, at(), field );
+}
+
+bool TQPSQLResult::reset ( const TQString& query )
+{
+ cleanup();
+ if ( !driver() )
+ return FALSE;
+ if ( !driver()->isOpen() || driver()->isOpenError() )
+ return FALSE;
+ setActive( FALSE );
+ setAt( TQSql::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", TQSqlError::Statement, d ) );
+ return FALSE;
+}
+
+int TQPSQLResult::size()
+{
+ return currentSize;
+}
+
+int TQPSQLResult::numRowsAffected()
+{
+ return TQString( 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 TQPSQLDriver::Protocol getPSQLVersion( PGconn* connection )
+{
+ PGresult* result = PQexec( connection, "select version()" );
+ int status = PQresultStatus( result );
+ if ( status == PGRES_COMMAND_OK || status == PGRES_TUPLES_OK ) {
+ TQString val( PQgetvalue( result, 0, 0 ) );
+ PQclear( result );
+ TQRegExp 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 TQPSQLDriver::Version6;
+ }
+ if ( vMaj == 6 ) {
+ return TQPSQLDriver::Version6;
+ } else if ( vMaj == 7 ) {
+ if ( vMin < 1 )
+ return TQPSQLDriver::Version7;
+ else if ( vMin < 3 )
+ return TQPSQLDriver::Version71;
+ }
+ return TQPSQLDriver::Version73;
+ }
+ } else {
+#ifdef QT_CHECK_RANGE
+ qWarning( "This version of PostgreSQL is not supported and may not work." );
+#endif
+ }
+
+ return TQPSQLDriver::Version6;
+}
+
+TQPSQLDriver::TQPSQLDriver( TQObject * parent, const char * name )
+ : TQSqlDriver(parent,name ? name : "TQPSQL"), pro( TQPSQLDriver::Version6 )
+{
+ init();
+}
+
+TQPSQLDriver::TQPSQLDriver( PGconn * conn, TQObject * parent, const char * name )
+ : TQSqlDriver(parent,name ? name : "TQPSQL"), pro( TQPSQLDriver::Version6 )
+{
+ init();
+ d->connection = conn;
+ if ( conn ) {
+ pro = getPSQLVersion( d->connection );
+ setOpen( TRUE );
+ setOpenError( FALSE );
+ }
+}
+
+void TQPSQLDriver::init()
+{
+ qSqlDriverExtDict()->insert( this, new TQPSQLDriverExtension(this) );
+ qSqlOpenExtDict()->insert( this, new TQPSQLOpenExtension(this) );
+
+ d = new TQPSQLPrivate();
+}
+
+TQPSQLDriver::~TQPSQLDriver()
+{
+ if ( d->connection )
+ PQfinish( d->connection );
+ delete d;
+ if ( !qSqlDriverExtDict()->isEmpty() ) {
+ TQSqlDriverExtension *ext = qSqlDriverExtDict()->take( this );
+ delete ext;
+ }
+ if ( !qSqlOpenExtDict()->isEmpty() ) {
+ TQSqlOpenExtension *ext = qSqlOpenExtDict()->take( this );
+ delete ext;
+ }
+}
+
+PGconn* TQPSQLDriver::connection()
+{
+ return d->connection;
+}
+
+
+bool TQPSQLDriver::hasFeature( DriverFeature f ) const
+{
+ switch ( f ) {
+ case Transactions:
+ return TRUE;
+ case QuerySize:
+ return TRUE;
+ case BLOB:
+ return pro >= TQPSQLDriver::Version71;
+ case Unicode:
+ return d->isUtf8;
+ default:
+ return FALSE;
+ }
+}
+
+bool TQPSQLDriver::open( const TQString&,
+ const TQString&,
+ const TQString&,
+ const TQString&,
+ int )
+{
+ qWarning("TQPSQLDriver::open(): This version of open() is no longer supported." );
+ return FALSE;
+}
+
+bool TQPSQLDriver::open( const TQString & db,
+ const TQString & user,
+ const TQString & password,
+ const TQString & host,
+ int port,
+ const TQString& connOpts )
+{
+ if ( isOpen() )
+ close();
+ TQString 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( TQString::number( port ) );
+
+ // add any connect options - the server will handle error detection
+ if ( !connOpts.isEmpty() )
+ connectString += " " + TQStringList::split( ';', connOpts ).join( " " );
+
+ d->connection = PQconnectdb( connectString.local8Bit().data() );
+ if ( PQstatus( d->connection ) == CONNECTION_BAD ) {
+ setLastError( qMakeError("Unable to connect", TQSqlError::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 TQPSQLDriver::close()
+{
+ if ( isOpen() ) {
+ if (d->connection)
+ PQfinish( d->connection );
+ d->connection = 0;
+ setOpen( FALSE );
+ setOpenError( FALSE );
+ }
+}
+
+TQSqlQuery TQPSQLDriver::createQuery() const
+{
+ return TQSqlQuery( new TQPSQLResult( this, d ) );
+}
+
+bool TQPSQLDriver::beginTransaction()
+{
+ if ( !isOpen() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQPSQLDriver::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", TQSqlError::Transaction, d ) );
+ return FALSE;
+ }
+ PQclear( res );
+ return TRUE;
+}
+
+bool TQPSQLDriver::commitTransaction()
+{
+ if ( !isOpen() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQPSQLDriver::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", TQSqlError::Transaction, d ) );
+ return FALSE;
+ }
+ PQclear( res );
+ return TRUE;
+}
+
+bool TQPSQLDriver::rollbackTransaction()
+{
+ if ( !isOpen() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQPSQLDriver::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", TQSqlError::Transaction, d ) );
+ PQclear( res );
+ return FALSE;
+ }
+ PQclear( res );
+ return TRUE;
+}
+
+TQStringList TQPSQLDriver::tables( const TQString& typeName ) const
+{
+ TQStringList tl;
+ if ( !isOpen() )
+ return tl;
+ int type = typeName.toInt();
+ TQSqlQuery t = createQuery();
+ t.setForwardOnly( TRUE );
+
+ if ( typeName.isEmpty() || ((type & (int)TQSql::Tables) == (int)TQSql::Tables) ) {
+
+ TQString query("select relname from pg_class where (relkind = 'r') "
+ "and (relname !~ '^Inv') "
+ "and (relname !~ '^pg_') ");
+ if (pro >= TQPSQLDriver::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)TQSql::Views) == (int)TQSql::Views ) {
+ TQString query("select relname from pg_class where ( relkind = 'v' ) "
+ "and ( relname !~ '^Inv' ) "
+ "and ( relname !~ '^pg_' ) ");
+ if (pro >= TQPSQLDriver::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)TQSql::SystemTables) == (int)TQSql::SystemTables ) {
+ TQString query( "select relname from pg_class where ( relkind = 'r' ) "
+ "and ( relname like 'pg_%' ) " );
+ if (pro >= TQPSQLDriver::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;
+}
+
+TQSqlIndex TQPSQLDriver::primaryIndex( const TQString& tablename ) const
+{
+ TQSqlIndex idx( tablename );
+ if ( !isOpen() )
+ return idx;
+ TQSqlQuery i = createQuery();
+ TQString stmt;
+
+ switch( pro ) {
+ case TQPSQLDriver::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 TQPSQLDriver::Version7:
+ case TQPSQLDriver::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 TQPSQLDriver::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() ) {
+ TQSqlField f( i.value(0).toString(), qDecodePSQLType( i.value(1).toInt() ) );
+ idx.append( f );
+ idx.setName( i.value(2).toString() );
+ }
+ return idx;
+}
+
+TQSqlRecord TQPSQLDriver::record( const TQString& tablename ) const
+{
+ TQSqlRecord fil;
+ if ( !isOpen() )
+ return fil;
+ TQString stmt;
+ switch( pro ) {
+ case TQPSQLDriver::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 TQPSQLDriver::Version7:
+ case TQPSQLDriver::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 TQPSQLDriver::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;
+ }
+
+ TQSqlQuery fi = createQuery();
+ fi.exec( stmt.arg( tablename.lower() ) );
+ while ( fi.next() ) {
+ TQSqlField f( fi.value(0).toString(), qDecodePSQLType( fi.value(1).toInt() ) );
+ fil.append( f );
+ }
+ return fil;
+}
+
+TQSqlRecord TQPSQLDriver::record( const TQSqlQuery& query ) const
+{
+ TQSqlRecord fil;
+ if ( !isOpen() )
+ return fil;
+ if ( query.isActive() && query.driver() == this ) {
+ TQPSQLResult* result = (TQPSQLResult*)query.result();
+ int count = PQnfields( result->d->result );
+ for ( int i = 0; i < count; ++i ) {
+ TQString name = PQfname( result->d->result, i );
+ TQVariant::Type type = qDecodePSQLType( PQftype( result->d->result, i ) );
+ TQSqlField rf( name, type );
+ fil.append( rf );
+ }
+ }
+ return fil;
+}
+
+TQSqlRecordInfo TQPSQLDriver::recordInfo( const TQString& tablename ) const
+{
+ TQSqlRecordInfo info;
+ if ( !isOpen() )
+ return info;
+
+ TQString stmt;
+ switch( pro ) {
+ case TQPSQLDriver::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 TQPSQLDriver::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 TQPSQLDriver::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 TQPSQLDriver::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;
+ }
+
+ TQSqlQuery query = createQuery();
+ query.exec( stmt.arg( tablename.lower() ) );
+ if ( pro >= TQPSQLDriver::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;
+ }
+ TQString defVal = query.value( 5 ).toString();
+ if ( !defVal.isEmpty() && defVal.startsWith( "'" ) )
+ defVal = defVal.mid( 1, defVal.length() - 2 );
+ info.append( TQSqlFieldInfo( 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() ) {
+ TQString defVal;
+ TQString stmt2 = "select pg_attrdef.adsrc from pg_attrdef where "
+ "pg_attrdef.adrelid = %1 and pg_attrdef.adnum = %2 ";
+ TQSqlQuery 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( TQSqlFieldInfo( query.value( 0 ).toString(),
+ qDecodePSQLType( query.value( 1 ).toInt() ),
+ query.value( 2 ).toBool(),
+ len,
+ precision,
+ defVal,
+ query.value( 1 ).toInt() ) );
+ }
+ }
+
+ return info;
+}
+
+TQSqlRecordInfo TQPSQLDriver::recordInfo( const TQSqlQuery& query ) const
+{
+ TQSqlRecordInfo info;
+ if ( !isOpen() )
+ return info;
+ if ( query.isActive() && query.driver() == this ) {
+ TQPSQLResult* result = (TQPSQLResult*)query.result();
+ int count = PQnfields( result->d->result );
+ for ( int i = 0; i < count; ++i ) {
+ TQString 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( TQSqlFieldInfo( name,
+ qDecodePSQLType( PQftype( result->d->result, i ) ),
+ -1,
+ len,
+ precision,
+ TQVariant(),
+ PQftype( result->d->result, i ) ) );
+ }
+ }
+ return info;
+}
+
+TQString TQPSQLDriver::formatValue( const TQSqlField* field,
+ bool ) const
+{
+ TQString r;
+ if ( field->isNull() ) {
+ r = nullText();
+ } else {
+ switch ( field->type() ) {
+ case TQVariant::DateTime:
+ if ( field->value().toDateTime().isValid() ) {
+ TQDate dt = field->value().toDateTime().date();
+ TQTime tm = field->value().toDateTime().time();
+ // msecs need to be right aligned otherwise psql
+ // interpretes them wrong
+ r = "'" + TQString::number( dt.year() ) + "-" +
+ TQString::number( dt.month() ) + "-" +
+ TQString::number( dt.day() ) + " " +
+ tm.toString() + "." +
+ TQString::number( tm.msec() ).rightJustify( 3, '0' ) + "'";
+ } else {
+ r = nullText();
+ }
+ break;
+ case TQVariant::Time:
+ if ( field->value().toTime().isValid() ) {
+ r = field->value().toTime().toString( TQt::ISODate );
+ } else {
+ r = nullText();
+ }
+ case TQVariant::String:
+ case TQVariant::CString: {
+ switch ( field->value().type() ) {
+ case TQVariant::Rect: {
+ TQRect rec = field->value().toRect();
+ // upper right corner then lower left according to psql docs
+ r = "'(" + TQString::number( rec.right() ) +
+ "," + TQString::number( rec.bottom() ) +
+ "),(" + TQString::number( rec.left() ) +
+ "," + TQString::number( rec.top() ) + ")'";
+ break;
+ }
+ case TQVariant::Point: {
+ TQPoint p = field->value().toPoint();
+ r = "'(" + TQString::number( p.x() ) +
+ "," + TQString::number( p.y() ) + ")'";
+ break;
+ }
+ case TQVariant::PointArray: {
+ TQPointArray pa = field->value().toPointArray();
+ r = "' ";
+ for ( int i = 0; i < (int)pa.size(); ++i ) {
+ r += "(" + TQString::number( pa[i].x() ) +
+ "," + TQString::number( pa[i].y() ) + "),";
+ }
+ r.truncate( r.length() - 1 );
+ r += "'";
+ break;
+ }
+ default:
+ // Escape '\' characters
+ r = TQSqlDriver::formatValue( field );
+ r.replace( "\\", "\\\\" );
+ break;
+ }
+ break;
+ }
+ case TQVariant::Bool:
+ if ( field->value().toBool() )
+ r = "TRUE";
+ else
+ r = "FALSE";
+ break;
+ case TQVariant::ByteArray: {
+ TQByteArray ba = field->value().asByteArray();
+ TQString 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 += TQString::number( (unsigned char) ba[ i ], 8 ).rightJustify( 3, '0', TRUE );
+ }
+ }
+ r += "'";
+ break;
+ }
+ default:
+ r = TQSqlDriver::formatValue( field );
+ break;
+ }
+ }
+ return r;
+}
diff --git a/src/sql/drivers/psql/qsql_psql.h b/src/sql/drivers/psql/qsql_psql.h
new file mode 100644
index 000000000..217cfe45e
--- /dev/null
+++ b/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 TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQL_PSQL_H
+#define TQSQL_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 TQPSQLPrivate;
+class TQPSQLDriver;
+class TQSqlRecordInfo;
+
+class TQPSQLResult : public TQSqlResult
+{
+ friend class TQPSQLDriver;
+public:
+ TQPSQLResult( const TQPSQLDriver* db, const TQPSQLPrivate* p );
+ ~TQPSQLResult();
+ PGresult* result();
+protected:
+ void cleanup();
+ bool fetch( int i );
+ bool fetchFirst();
+ bool fetchLast();
+ TQVariant data( int i );
+ bool isNull( int field );
+ bool reset ( const TQString& query );
+ int size();
+ int numRowsAffected();
+private:
+ int currentSize;
+ TQPSQLPrivate* d;
+};
+
+class Q_EXPORT_SQLDRIVER_PSQL TQPSQLDriver : public TQSqlDriver
+{
+public:
+ enum Protocol {
+ Version6 = 6,
+ Version7 = 7,
+ Version71 = 8,
+ Version73 = 9
+ };
+
+ TQPSQLDriver( TQObject * parent=0, const char * name=0 );
+ TQPSQLDriver( PGconn * conn, TQObject * parent=0, const char * name=0 );
+ ~TQPSQLDriver();
+ bool hasFeature( DriverFeature f ) const;
+ bool open( const TQString & db,
+ const TQString & user = TQString::null,
+ const TQString & password = TQString::null,
+ const TQString & host = TQString::null,
+ int port = -1 );
+ void close();
+ TQSqlQuery createQuery() const;
+ TQStringList tables( const TQString& user ) const;
+ TQSqlIndex primaryIndex( const TQString& tablename ) const;
+ TQSqlRecord record( const TQString& tablename ) const;
+ TQSqlRecord record( const TQSqlQuery& query ) const;
+ TQSqlRecordInfo recordInfo( const TQString& tablename ) const;
+ TQSqlRecordInfo recordInfo( const TQSqlQuery& query ) const;
+
+ Protocol protocol() const { return pro; }
+ PGconn* connection();
+ TQString formatValue( const TQSqlField* field,
+ bool trimStrings ) const;
+
+ // ### remove me for 4.0
+ bool open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts );
+protected:
+ bool beginTransaction();
+ bool commitTransaction();
+ bool rollbackTransaction();
+private:
+ void init();
+ Protocol pro;
+ TQPSQLPrivate* d;
+};
+
+#endif
diff --git a/src/sql/drivers/sqlite/qsql_sqlite.cpp b/src/sql/drivers/sqlite/qsql_sqlite.cpp
new file mode 100644
index 000000000..ecdda1c0c
--- /dev/null
+++ b/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 TQt 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 TQSQLITE_DRIVER_NAME "TQSQLITE"
+
+static TQSqlVariant::Type nameToType(const TQString& typeName)
+{
+ TQString tName = typeName.upper();
+ if (tName.startsWith("INT"))
+ return TQSqlVariant::Int;
+ if (tName.startsWith("FLOAT") || tName.startsWith("NUMERIC"))
+ return TQSqlVariant::Double;
+ if (tName.startsWith("BOOL"))
+ return TQSqlVariant::Bool;
+ // SQLite is typeless - consider everything else as string
+ return TQSqlVariant::String;
+}
+
+class TQSQLiteDriverPrivate
+{
+public:
+ TQSQLiteDriverPrivate();
+ sqlite *access;
+ bool utf8;
+};
+
+TQSQLiteDriverPrivate::TQSQLiteDriverPrivate() : access(0)
+{
+ utf8 = (qstrcmp(sqlite_encoding, "UTF-8") == 0);
+}
+
+class TQSQLiteResultPrivate
+{
+public:
+ TQSQLiteResultPrivate(TQSQLiteResult *res);
+ void cleanup();
+ bool fetchNext(TQtSqlCachedResult::RowCache *row);
+ bool isSelect();
+ // initializes the recordInfo and the cache
+ void init(const char **cnames, int numCols, TQtSqlCachedResult::RowCache **row = 0);
+ void finalize();
+
+ TQSQLiteResult* 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
+ TQtSqlCachedResult::RowCache *skipRow;
+
+ uint utf8: 1;
+ TQSqlRecordInfo rInf;
+};
+
+static const uint initial_cache_size = 128;
+
+TQSQLiteResultPrivate::TQSQLiteResultPrivate(TQSQLiteResult* res) : q(res), access(0), currentTail(0),
+ currentMachine(0), skippedStatus(FALSE), skipRow(0), utf8(FALSE)
+{
+}
+
+void TQSQLiteResultPrivate::cleanup()
+{
+ finalize();
+ rInf.clear();
+ currentTail = 0;
+ currentMachine = 0;
+ skippedStatus = FALSE;
+ delete skipRow;
+ skipRow = 0;
+ q->setAt(TQSql::BeforeFirst);
+ q->setActive(FALSE);
+ q->cleanup();
+}
+
+void TQSQLiteResultPrivate::finalize()
+{
+ if (!currentMachine)
+ return;
+
+ char* err = 0;
+ int res = sqlite_finalize(currentMachine, &err);
+ if (err) {
+ q->setLastError(TQSqlError("Unable to fetch results", err, TQSqlError::Statement, res));
+ sqlite_freemem(err);
+ }
+ currentMachine = 0;
+}
+
+// called on first fetch
+void TQSQLiteResultPrivate::init(const char **cnames, int numCols, TQtSqlCachedResult::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(TQSqlFieldInfo(fieldName, nameToType(cnames[i+numCols])));
+ }
+ // skip the first fetch
+ if (row && !*row) {
+ *row = new TQtSqlCachedResult::RowCache(numCols);
+ skipRow = *row;
+ }
+}
+
+bool TQSQLiteResultPrivate::fetchNext(TQtSqlCachedResult::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 ? TQString::fromUtf8(fvals[i]) : TQString(fvals[i]);
+ return TRUE;
+ case SQLITE_DONE:
+ if (rInf.isEmpty())
+ // must be first call.
+ init(cnames, colNum);
+ q->setAt(TQSql::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(TQSql::AfterLast);
+ return FALSE;
+ }
+ return FALSE;
+}
+
+TQSQLiteResult::TQSQLiteResult(const TQSQLiteDriver* db)
+: TQtSqlCachedResult(db)
+{
+ d = new TQSQLiteResultPrivate(this);
+ d->access = db->d->access;
+ d->utf8 = db->d->utf8;
+}
+
+TQSQLiteResult::~TQSQLiteResult()
+{
+ d->cleanup();
+ delete d;
+}
+
+/*
+ Execute \a query.
+*/
+bool TQSQLiteResult::reset (const TQString& 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(TQSqlError("Unable to execute statement", err, TQSqlError::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 TQSQLiteResult::gotoNext(TQtSqlCachedResult::RowCache* row)
+{
+ return d->fetchNext(row);
+}
+
+int TQSQLiteResult::size()
+{
+ return -1;
+}
+
+int TQSQLiteResult::numRowsAffected()
+{
+ return sqlite_changes(d->access);
+}
+
+/////////////////////////////////////////////////////////
+
+TQSQLiteDriver::TQSQLiteDriver(TQObject * parent, const char * name)
+ : TQSqlDriver(parent, name ? name : TQSQLITE_DRIVER_NAME)
+{
+ d = new TQSQLiteDriverPrivate();
+}
+
+TQSQLiteDriver::TQSQLiteDriver(sqlite *connection, TQObject *parent, const char *name)
+ : TQSqlDriver(parent, name ? name : TQSQLITE_DRIVER_NAME)
+{
+ d = new TQSQLiteDriverPrivate();
+ d->access = connection;
+ setOpen(TRUE);
+ setOpenError(FALSE);
+}
+
+
+TQSQLiteDriver::~TQSQLiteDriver()
+{
+ delete d;
+}
+
+bool TQSQLiteDriver::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 TQSQLiteDriver::open(const TQString & db, const TQString &, const TQString &, const TQString &, int, const TQString &)
+{
+ if (isOpen())
+ close();
+
+ if (db.isEmpty())
+ return FALSE;
+
+ char* err = 0;
+ d->access = sqlite_open(TQFile::encodeName(db), 0, &err);
+ if (err) {
+ setLastError(TQSqlError("Error to open database", err, TQSqlError::Connection));
+ sqlite_freemem(err);
+ err = 0;
+ }
+
+ if (d->access) {
+ setOpen(TRUE);
+ setOpenError(FALSE);
+ return TRUE;
+ }
+ setOpenError(TRUE);
+ return FALSE;
+}
+
+void TQSQLiteDriver::close()
+{
+ if (isOpen()) {
+ sqlite_close(d->access);
+ d->access = 0;
+ setOpen(FALSE);
+ setOpenError(FALSE);
+ }
+}
+
+TQSqlQuery TQSQLiteDriver::createQuery() const
+{
+ return TQSqlQuery(new TQSQLiteResult(this));
+}
+
+bool TQSQLiteDriver::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(TQSqlError("Unable to begin transaction", err, TQSqlError::Transaction, res));
+ sqlite_freemem(err);
+ return FALSE;
+}
+
+bool TQSQLiteDriver::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(TQSqlError("Unable to commit transaction", err, TQSqlError::Transaction, res));
+ sqlite_freemem(err);
+ return FALSE;
+}
+
+bool TQSQLiteDriver::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(TQSqlError("Unable to rollback Transaction", err, TQSqlError::Transaction, res));
+ sqlite_freemem(err);
+ return FALSE;
+}
+
+TQStringList TQSQLiteDriver::tables(const TQString &typeName) const
+{
+ TQStringList res;
+ if (!isOpen())
+ return res;
+ int type = typeName.toInt();
+
+ TQSqlQuery q = createQuery();
+ q.setForwardOnly(TRUE);
+#if (QT_VERSION-0 >= 0x030000)
+ if ((type & (int)TQSql::Tables) && (type & (int)TQSql::Views))
+ q.exec("SELECT name FROM sqlite_master WHERE type='table' OR type='view'");
+ else if (typeName.isEmpty() || (type & (int)TQSql::Tables))
+ q.exec("SELECT name FROM sqlite_master WHERE type='table'");
+ else if (type & (int)TQSql::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)TQSql::SystemTables) {
+ // there are no internal tables beside this one:
+ res.append("sqlite_master");
+ }
+#endif
+
+ return res;
+}
+
+TQSqlIndex TQSQLiteDriver::primaryIndex(const TQString &tblname) const
+{
+ TQSqlRecordInfo rec(recordInfo(tblname)); // expensive :(
+
+ if (!isOpen())
+ return TQSqlIndex();
+
+ TQSqlQuery q = createQuery();
+ q.setForwardOnly(TRUE);
+ // finrst find a UNITQUE INDEX
+ q.exec("PRAGMA index_list('" + tblname + "');");
+ TQString indexname;
+ while(q.next()) {
+ if (q.value(2).toInt()==1) {
+ indexname = q.value(1).toString();
+ break;
+ }
+ }
+ if (indexname.isEmpty())
+ return TQSqlIndex();
+
+ q.exec("PRAGMA index_info('" + indexname + "');");
+
+ TQSqlIndex index(tblname, indexname);
+ while(q.next()) {
+ TQString name = q.value(2).toString();
+ TQSqlVariant::Type type = TQSqlVariant::Invalid;
+ if (rec.contains(name))
+ type = rec.find(name).type();
+ index.append(TQSqlField(name, type));
+ }
+ return index;
+}
+
+TQSqlRecordInfo TQSQLiteDriver::recordInfo(const TQString &tbl) const
+{
+ if (!isOpen())
+ return TQSqlRecordInfo();
+
+ TQSqlQuery q = createQuery();
+ q.setForwardOnly(TRUE);
+ q.exec("SELECT * FROM " + tbl + " LIMIT 1");
+ return recordInfo(q);
+}
+
+TQSqlRecord TQSQLiteDriver::record(const TQString &tblname) const
+{
+ if (!isOpen())
+ return TQSqlRecord();
+
+ return recordInfo(tblname).toRecord();
+}
+
+TQSqlRecord TQSQLiteDriver::record(const TQSqlQuery& query) const
+{
+ if (query.isActive() && query.driver() == this) {
+ TQSQLiteResult* result = (TQSQLiteResult*)query.result();
+ return result->d->rInf.toRecord();
+ }
+ return TQSqlRecord();
+}
+
+TQSqlRecordInfo TQSQLiteDriver::recordInfo(const TQSqlQuery& query) const
+{
+ if (query.isActive() && query.driver() == this) {
+ TQSQLiteResult* result = (TQSQLiteResult*)query.result();
+ return result->d->rInf;
+ }
+ return TQSqlRecordInfo();
+}
diff --git a/src/sql/drivers/sqlite/qsql_sqlite.h b/src/sql/drivers/sqlite/qsql_sqlite.h
new file mode 100644
index 000000000..ccde9b865
--- /dev/null
+++ b/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 TQt 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 TQSQL_SQLITE_H
+#define TQSQL_SQLITE_H
+
+#include <qsqldriver.h>
+#include <qsqlresult.h>
+#include <qsqlrecord.h>
+#include <qsqlindex.h>
+#include "../cache/qsqlcachedresult.h"
+
+#if (QT_VERSION-0 >= 0x030000)
+typedef TQVariant TQSqlVariant;
+#endif
+
+#if defined (Q_OS_WIN32)
+# include <qt_windows.h>
+#endif
+
+class TQSQLiteDriverPrivate;
+class TQSQLiteResultPrivate;
+class TQSQLiteDriver;
+struct sqlite;
+
+class TQSQLiteResult : public TQtSqlCachedResult
+{
+ friend class TQSQLiteDriver;
+ friend class TQSQLiteResultPrivate;
+public:
+ TQSQLiteResult(const TQSQLiteDriver* db);
+ ~TQSQLiteResult();
+
+protected:
+ bool gotoNext(TQtSqlCachedResult::RowCache* row);
+ bool reset (const TQString& query);
+ int size();
+ int numRowsAffected();
+
+private:
+ TQSQLiteResultPrivate* d;
+};
+
+class TQSQLiteDriver : public TQSqlDriver
+{
+ friend class TQSQLiteResult;
+public:
+ TQSQLiteDriver(TQObject *parent = 0, const char *name = 0);
+ TQSQLiteDriver(sqlite *connection, TQObject *parent = 0, const char *name = 0);
+ ~TQSQLiteDriver();
+ bool hasFeature(DriverFeature f) const;
+ bool open(const TQString & db,
+ const TQString & user,
+ const TQString & password,
+ const TQString & host,
+ int port,
+ const TQString & connOpts);
+ bool open( const TQString & db,
+ const TQString & user,
+ const TQString & password,
+ const TQString & host,
+ int port ) { return open (db, user, password, host, port, TQString()); }
+ void close();
+ TQSqlQuery createQuery() const;
+ bool beginTransaction();
+ bool commitTransaction();
+ bool rollbackTransaction();
+ TQStringList tables(const TQString& user) const;
+
+ TQSqlRecord record(const TQString& tablename) const;
+ TQSqlRecordInfo recordInfo(const TQString& tablename) const;
+ TQSqlIndex primaryIndex(const TQString &table) const;
+ TQSqlRecord record(const TQSqlQuery& query) const;
+ TQSqlRecordInfo recordInfo(const TQSqlQuery& query) const;
+
+private:
+ TQSQLiteDriverPrivate* d;
+};
+#endif
diff --git a/src/sql/qdatabrowser.cpp b/src/sql/qdatabrowser.cpp
new file mode 100644
index 000000000..b1dc0bddd
--- /dev/null
+++ b/src/sql/qdatabrowser.cpp
@@ -0,0 +1,1284 @@
+/****************************************************************************
+**
+** Implementation of TQDataBrowser class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQDataBrowserPrivate
+{
+public:
+ TQDataBrowserPrivate() : boundaryCheck( TRUE ), readOnly( FALSE ) {}
+ TQSqlCursorManager cur;
+ TQSqlFormManager frm;
+ TQDataManager dat;
+ bool boundaryCheck;
+ bool readOnly;
+};
+
+/*!
+ \class TQDataBrowser qdatabrowser.h
+ \brief The TQDataBrowser 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
+ TQDataView; if you want a table-based presentation of your data use
+ TQDataTable.
+
+ A TQDataBrowser is used to associate a dataset with a form in much
+ the same way as a TQDataTable 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 TQDataBrowser::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.
+*/
+
+TQDataBrowser::TQDataBrowser( TQWidget *parent, const char *name, WFlags fl )
+ : TQWidget( parent, name, fl )
+{
+ d = new TQDataBrowserPrivate();
+ d->dat.setMode( TQSql::Update );
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQDataBrowser::~TQDataBrowser()
+{
+ 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 TQDataBrowser::Boundary.
+
+ \sa Boundary
+*/
+
+TQDataBrowser::Boundary TQDataBrowser::boundary()
+{
+ TQSqlCursor* cur = d->cur.cursor();
+ if ( !cur || !cur->isActive() )
+ return Unknown;
+ if ( !cur->isValid() ) {
+ if ( cur->at() == TQSql::BeforeFirst )
+ return BeforeBeginning;
+ if ( cur->at() == TQSql::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 TQDataBrowser::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 TQDataBrowser::setBoundaryChecking( bool active )
+{
+ d->boundaryCheck = active;
+}
+
+bool TQDataBrowser::boundaryChecking() const
+{
+ return d->boundaryCheck;
+}
+
+/*!
+ \property TQDataBrowser::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
+ TQStringList list = myDataBrowser.sort();
+ TQStringList::Iterator it = list.begin();
+ while( it != list.end() ) {
+ myProcessing( *it );
+ ++it;
+ }
+ \endcode
+*/
+
+void TQDataBrowser::setSort( const TQStringList& sort )
+{
+ d->cur.setSort( sort );
+}
+
+/*!
+ \overload
+
+ Sets the data browser's sort to the TQSqlIndex \a sort. To apply
+ the new sort, use refresh().
+
+*/
+void TQDataBrowser::setSort( const TQSqlIndex& sort )
+{
+ d->cur.setSort( sort );
+}
+
+TQStringList TQDataBrowser::sort() const
+{
+ return d->cur.sort();
+}
+
+
+/*!
+ \property TQDataBrowser::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 TQDataBrowser::setFilter( const TQString& filter )
+{
+ d->cur.setFilter( filter );
+}
+
+
+TQString TQDataBrowser::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 TQDataBrowser::setSqlCursor( TQSqlCursor* 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()
+*/
+
+TQSqlCursor* TQDataBrowser::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 TQDataBrowser::setForm( TQSqlForm* form )
+{
+ d->frm.setForm( form );
+}
+
+
+/*!
+ Returns the data browser's default form or 0 if no form has been
+ set.
+*/
+
+TQSqlForm* TQDataBrowser::form()
+{
+ return d->frm.form();
+}
+
+/*!
+ \property TQDataBrowser::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 TQDataBrowser::setReadOnly( bool active )
+{
+ d->readOnly = active;
+}
+
+bool TQDataBrowser::isReadOnly() const
+{
+ return d->readOnly;
+}
+
+void TQDataBrowser::setConfirmEdits( bool confirm )
+{
+ d->dat.setConfirmEdits( confirm );
+}
+
+/*!
+ \property TQDataBrowser::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 TQDataBrowser::setConfirmInsert( bool confirm )
+{
+ d->dat.setConfirmInsert( confirm );
+}
+
+/*!
+ \property TQDataBrowser::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 TQDataBrowser::setConfirmUpdate( bool confirm )
+{
+ d->dat.setConfirmUpdate( confirm );
+}
+
+/*!
+ \property TQDataBrowser::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 TQDataBrowser::setConfirmDelete( bool confirm )
+{
+ d->dat.setConfirmDelete( confirm );
+}
+
+/*!
+ \property TQDataBrowser::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 TQDataBrowser::confirmEdits() const
+{
+ return ( d->dat.confirmEdits() );
+}
+
+bool TQDataBrowser::confirmInsert() const
+{
+ return ( d->dat.confirmInsert() );
+}
+
+bool TQDataBrowser::confirmUpdate() const
+{
+ return ( d->dat.confirmUpdate() );
+}
+
+bool TQDataBrowser::confirmDelete() const
+{
+ return ( d->dat.confirmDelete() );
+}
+
+/*!
+ \property TQDataBrowser::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 TQDataBrowser::setConfirmCancels( bool confirm )
+{
+ d->dat.setConfirmCancels( confirm );
+}
+
+bool TQDataBrowser::confirmCancels() const
+{
+ return d->dat.confirmCancels();
+}
+
+/*!
+ \property TQDataBrowser::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 TQDataBrowser::setAutoEdit( bool autoEdit )
+{
+ d->dat.setAutoEdit( autoEdit );
+}
+
+bool TQDataBrowser::autoEdit() const
+{
+ return d->dat.autoEdit();
+}
+
+/*!
+ \fn void TQDataBrowser::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 TQDataBrowser::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 TQDataBrowser::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 TQDataBrowser::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 TQDataBrowser::currentChanged( const TQSqlRecord* 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 TQDataBrowser::primeInsert( TQSqlRecord* 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 TQSqlCursor::primeInsert() is \e not called on the
+ default cursor, as this would corrupt values in the form.)
+
+ \sa insert()
+*/
+
+
+/*!
+ \fn void TQDataBrowser::primeUpdate( TQSqlRecord* 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 TQSqlCursor::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 TQDataBrowser::primeDelete( TQSqlRecord* 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 TQSqlCursor::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 TQDataBrowser::cursorChanged( TQSqlCursor::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 TQSqlCursor::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 TQDataBrowser::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 TQSqlCursor::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 TQDataBrowser::insert()
+{
+ TQSqlRecord* buf = d->frm.record();
+ TQSqlCursor* cur = d->cur.cursor();
+ if ( !buf || !cur )
+ return;
+ bool doIns = TRUE;
+ TQSql::Confirm conf = TQSql::Yes;
+ switch ( d->dat.mode() ) {
+ case TQSql::Insert:
+ if ( autoEdit() ) {
+ if ( confirmInsert() )
+ conf = confirmEdit( TQSql::Insert );
+ switch ( conf ) {
+ case TQSql::Yes:
+ insertCurrent();
+ break;
+ case TQSql::No:
+ break;
+ case TQSql::Cancel:
+ doIns = FALSE;
+ break;
+ }
+ }
+ break;
+ default:
+ if ( autoEdit() && currentEdited() ) {
+ if ( confirmUpdate() )
+ conf = confirmEdit( TQSql::Update );
+ switch ( conf ) {
+ case TQSql::Yes:
+ updateCurrent();
+ break;
+ case TQSql::No:
+ break;
+ case TQSql::Cancel:
+ doIns = FALSE;
+ break;
+ }
+ }
+ break;
+ }
+ if ( doIns ) {
+ d->dat.setMode( TQSql::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 TQDataBrowser::update()
+{
+ TQSqlRecord* buf = d->frm.record();
+ TQSqlCursor* cur = d->cur.cursor();
+ if ( !buf || !cur )
+ return;
+ TQSql::Confirm conf = TQSql::Yes;
+ switch ( d->dat.mode() ){
+ case TQSql::Insert:
+ if ( confirmInsert() )
+ conf = confirmEdit( TQSql::Insert );
+ switch ( conf ) {
+ case TQSql::Yes:
+ if ( insertCurrent() )
+ d->dat.setMode( TQSql::Update );
+ break;
+ case TQSql::No:
+ d->dat.setMode( TQSql::Update );
+ cur->editBuffer( TRUE );
+ readFields();
+ break;
+ case TQSql::Cancel:
+ break;
+ }
+ break;
+ default:
+ d->dat.setMode( TQSql::Update );
+ if ( confirmUpdate() )
+ conf = confirmEdit( TQSql::Update );
+ switch ( conf ) {
+ case TQSql::Yes:
+ updateCurrent();
+ break;
+ case TQSql::No:
+ case TQSql::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 TQDataBrowser::del()
+{
+ TQSqlRecord* buf = d->frm.record();
+ TQSqlCursor* cur = d->cur.cursor();
+ if ( !buf || !cur )
+ return;
+ TQSql::Confirm conf = TQSql::Yes;
+ switch ( d->dat.mode() ){
+ case TQSql::Insert:
+ if ( confirmCancels() )
+ conf = confirmCancel( TQSql::Insert );
+ if ( conf == TQSql::Yes ) {
+ cur->editBuffer( TRUE ); /* restore from cursor */
+ readFields();
+ d->dat.setMode( TQSql::Update );
+ } else
+ d->dat.setMode( TQSql::Insert );
+ break;
+ default:
+ if ( confirmDelete() )
+ conf = confirmEdit( TQSql::Delete );
+ switch ( conf ) {
+ case TQSql::Yes:
+ emit primeDelete( buf );
+ deleteCurrent();
+ break;
+ case TQSql::No:
+ case TQSql::Cancel:
+ break;
+ }
+ d->dat.setMode( TQSql::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 TQDataBrowser::seek( int i, bool relative )
+{
+ int b = 0;
+ TQSqlCursor* 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 TQDataBrowser::first()
+{
+ nav( &TQSqlCursor::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 TQDataBrowser::last()
+{
+ nav( &TQSqlCursor::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 TQDataBrowser::next()
+{
+ nav( &TQSqlCursor::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 TQDataBrowser::prev()
+{
+ nav( &TQSqlCursor::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 TQDataBrowser::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 TQDataBrowser::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 TQSqlPropertyMap constructor for the default
+ mappings of widgets to properties.
+*/
+
+void TQDataBrowser::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 TQDataBrowser::insertCurrent()
+{
+ if ( isReadOnly() )
+ return FALSE;
+ TQSqlRecord* buf = d->frm.record();
+ TQSqlCursor* 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( TQSqlCursor::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 TQDataBrowser::updateCurrent()
+{
+ if ( isReadOnly() )
+ return FALSE;
+ TQSqlRecord* buf = d->frm.record();
+ TQSqlCursor* 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( TQSqlCursor::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 TQDataBrowser::deleteCurrent()
+{
+ if ( isReadOnly() )
+ return FALSE;
+ TQSqlRecord* buf = d->frm.record();
+ TQSqlCursor* 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( TQSqlCursor::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 TQDataBrowser::currentEdited()
+{
+ TQSqlRecord* buf = d->frm.record();
+ TQSqlCursor* 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 TQDataBrowser::preNav()
+{
+ TQSqlRecord* buf = d->frm.record();
+ TQSqlCursor* cur = d->cur.cursor();
+ if ( !buf || !cur )
+ return FALSE;
+
+ if ( !isReadOnly() && autoEdit() && currentEdited() ) {
+ bool ok = TRUE;
+ TQSql::Confirm conf = TQSql::Yes;
+ switch ( d->dat.mode() ){
+ case TQSql::Insert:
+ if ( confirmInsert() )
+ conf = confirmEdit( TQSql::Insert );
+ switch ( conf ) {
+ case TQSql::Yes:
+ ok = insertCurrent();
+ d->dat.setMode( TQSql::Update );
+ break;
+ case TQSql::No:
+ d->dat.setMode( TQSql::Update );
+ break;
+ case TQSql::Cancel:
+ return FALSE;
+ }
+ break;
+ default:
+ if ( confirmUpdate() )
+ conf = confirmEdit( TQSql::Update );
+ switch ( conf ) {
+ case TQSql::Yes:
+ ok = updateCurrent();
+ break;
+ case TQSql::No:
+ break;
+ case TQSql::Cancel:
+ return FALSE;
+ }
+ }
+ return ok;
+ }
+ return TRUE;
+}
+
+/*! \internal
+
+ Handles post-navigation according to \a primeUpd.
+*/
+
+void TQDataBrowser::postNav( bool primeUpd )
+{
+ if ( primeUpd ) {
+ TQSqlRecord* buf = d->frm.record();
+ TQSqlCursor* 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 TQDataBrowser::nav( Nav nav )
+{
+ int b = 0;
+ TQSqlCursor* 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 TQDataBrowser::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 TQDataBrowser::handleError( const TQSqlError& 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.
+*/
+
+TQSql::Confirm TQDataBrowser::confirmEdit( TQSql::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.
+*/
+
+TQSql::Confirm TQDataBrowser::confirmCancel( TQSql::Op m )
+{
+ return d->dat.confirmCancel( this, m );
+}
+
+/*!
+ \fn void TQDataBrowser::beforeInsert( TQSqlRecord* 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 TQDataBrowser::beforeUpdate( TQSqlRecord* 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 TQDataBrowser::beforeDelete( TQSqlRecord* 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/src/sql/qdatabrowser.h b/src/sql/qdatabrowser.h
new file mode 100644
index 000000000..b7aee2bf8
--- /dev/null
+++ b/src/sql/qdatabrowser.h
@@ -0,0 +1,177 @@
+/****************************************************************************
+**
+** Definition of TQDataBrowser class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQDATABROWSER_H
+#define TQDATABROWSER_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 TQSqlForm;
+class TQDataBrowserPrivate;
+
+class Q_EXPORT TQDataBrowser : public TQWidget
+{
+ Q_OBJECT
+ Q_PROPERTY( bool boundaryChecking READ boundaryChecking WRITE setBoundaryChecking )
+ Q_PROPERTY( TQString filter READ filter WRITE setFilter )
+ Q_PROPERTY( TQStringList 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:
+ TQDataBrowser( TQWidget* parent=0, const char* name=0, WFlags fl = 0 );
+ ~TQDataBrowser();
+
+ enum Boundary {
+ Unknown,
+ None,
+ BeforeBeginning,
+ Beginning,
+ End,
+ AfterEnd
+ };
+
+ Boundary boundary();
+ void setBoundaryChecking( bool active );
+ bool boundaryChecking() const;
+
+ void setSort( const TQSqlIndex& sort );
+ void setSort( const TQStringList& sort );
+ TQStringList sort() const;
+ void setFilter( const TQString& filter );
+ TQString filter() const;
+ virtual void setSqlCursor( TQSqlCursor* cursor, bool autoDelete = FALSE );
+ TQSqlCursor* sqlCursor() const;
+ virtual void setForm( TQSqlForm* form );
+ TQSqlForm* 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 TQSqlRecord* record );
+ void primeInsert( TQSqlRecord* buf );
+ void primeUpdate( TQSqlRecord* buf );
+ void primeDelete( TQSqlRecord* buf );
+ void beforeInsert( TQSqlRecord* buf );
+ void beforeUpdate( TQSqlRecord* buf );
+ void beforeDelete( TQSqlRecord* buf );
+ void cursorChanged( TQSqlCursor::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 TQSql::Confirm confirmEdit( TQSql::Op m );
+ virtual TQSql::Confirm confirmCancel( TQSql::Op m );
+
+ virtual void handleError( const TQSqlError& error );
+
+private:
+ typedef bool (TQSqlCursor::*Nav)();
+ bool preNav();
+ void postNav( bool primeUpd );
+ void nav( Nav nav );
+ TQDataBrowserPrivate* d;
+
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ TQDataBrowser( const TQDataBrowser & );
+ TQDataBrowser &operator=( const TQDataBrowser & );
+#endif
+};
+
+
+#endif
+#endif
diff --git a/src/sql/qdatatable.cpp b/src/sql/qdatatable.cpp
new file mode 100644
index 000000000..8edc7f230
--- /dev/null
+++ b/src/sql/qdatatable.cpp
@@ -0,0 +1,2322 @@
+/****************************************************************************
+**
+** Implementation of TQDataTable class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQDataTablePrivate
+{
+public:
+ TQDataTablePrivate()
+ : 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 )
+ {}
+ ~TQDataTablePrivate() { if ( propertyMap ) delete propertyMap; }
+
+ TQString nullTxt;
+ bool nullTxtChanged;
+ typedef TQValueList< uint > ColIndex;
+ ColIndex colIndex;
+ bool haveAllRows;
+ bool continuousEdit;
+ TQSqlEditorFactory* editorFactory;
+ TQSqlPropertyMap* propertyMap;
+ TQString trueTxt;
+ TQt::DateFormat datefmt;
+ TQString falseTxt;
+ int editRow;
+ int editCol;
+ int insertRowLast;
+ TQString insertHeaderLabelLast;
+ int insertPreRows;
+ TQSqlRecord* editBuffer;
+ bool cancelMode;
+ bool cancelInsert;
+ bool cancelUpdate;
+ int lastAt;
+ TQString ftr;
+ TQStringList srt;
+ TQStringList fld;
+ TQStringList fldLabel;
+ TQValueList<int> fldWidth;
+ TQValueList<TQIconSet> fldIcon;
+ TQValueList<bool> fldHidden;
+ TQSqlCursorManager cur;
+ TQDataManager dat;
+};
+
+#ifdef QT_DEBUG_DATATABLE
+void qt_debug_buffer( const TQString& msg, TQSqlRecord* cursor )
+{
+ qDebug("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+ qDebug(msg);
+ for ( uint j = 0; j < cursor->count(); ++j ) {
+ qDebug(cursor->field(j)->name() + " type:" + TQString(cursor->field(j)->value().typeName()) + " value:" + cursor->field(j)->value().toString() );
+ }
+}
+#endif
+
+/*!
+ \enum TQDataTable::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 TQDataTable qdatatable.h
+ \brief The TQDataTable class provides a flexible SQL table widget that supports browsing and editing.
+
+ \ingroup database
+ \mainclass
+ \module sql
+
+ TQDataTable supports various functions for presenting and editing
+ SQL data from a \l TQSqlCursor in a table.
+
+ If you want a to present your data in a form use TQDataBrowser, or
+ for read-only forms, TQDataView.
+
+ When displaying data, TQDataTable only retrieves data for visible
+ rows. If the driver supports the 'query size' property the
+ TQDataTable 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
+ tquickly as possible, with minimum memory usage.
+
+ TQDataTable inherits TQTable'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 TQSqlCursor).
+ TQDataTable 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 TQSqlCursor 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.
+
+ TQDataTable creates editors using the default \l TQSqlEditorFactory.
+ 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 TQString with text() or as
+ a TQVariant 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 TQSqlSelectCursor 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.
+*/
+
+TQDataTable::TQDataTable ( TQWidget * parent, const char * name )
+ : TQTable( 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.
+*/
+
+TQDataTable::TQDataTable ( TQSqlCursor* cursor, bool autoPopulate, TQWidget * parent, const char * name )
+ : TQTable( parent, name )
+{
+ init();
+ setSqlCursor( cursor, autoPopulate );
+}
+
+/*! \internal
+*/
+
+
+void TQDataTable::init()
+{
+ d = new TQDataTablePrivate();
+ setAutoEdit( TRUE );
+ setSelectionMode( SingleRow );
+ setFocusStyle( FollowStyle );
+ d->trueTxt = tr( "True" );
+ d->falseTxt = tr( "False" );
+ d->datefmt = TQt::LocalDate;
+ reset();
+ connect( this, SIGNAL( selectionChanged() ),
+ SLOT( updateCurrentSelection()));
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQDataTable::~TQDataTable()
+{
+ 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 TQDataTable::addColumn( const TQString& fieldName,
+ const TQString& label,
+ int width,
+ const TQIconSet& 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 TQDataTable::setColumn( uint col, const TQString& fieldName,
+ const TQString& label,
+ int width,
+ const TQIconSet& 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 TQSqlField
+*/
+
+void TQDataTable::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 TQTable
+ the TQDataTable is not immediately redrawn, you must call
+ refresh(TQDataTable::RefreshColumns)
+ yourself.
+
+ \sa refresh()
+*/
+void TQDataTable::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 TQSqlCursor 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 TQDataTable::adjustColumn( int col )
+{
+ TQSqlCursor * 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( TQSql::BeforeFirst );
+ while ( cur->next() ) {
+ w = TQMAX( w, fontMetrics().width( fieldToString( cur->field( indexOf( col ) ) ) ) + 10 );
+ }
+ setColumnWidth( col, w );
+ cur->seek( oldRow );
+ refresh( RefreshColumns );
+}
+
+/*! \reimp
+*/
+void TQDataTable::setColumnStretchable( int col, bool s )
+{
+ if ( numCols() == 0 ) {
+ refresh( RefreshColumns );
+ }
+ if ( numCols() > col ) {
+ TQTable::setColumnStretchable( col, s );
+ }
+}
+
+TQString TQDataTable::filter() const
+{
+ return d->cur.filter();
+}
+
+/*!
+ \property TQDataTable::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 TQDataTable::setFilter( const TQString& filter )
+{
+ d->cur.setFilter( filter );
+}
+
+
+/*!
+ \property TQDataTable::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
+ TQStringList list = myDataTable.sort();
+ TQStringList::Iterator it = list.begin();
+ while( it != list.end() ) {
+ myProcessing( *it );
+ ++it;
+ }
+ \endcode
+
+ \sa filter() refresh()
+*/
+
+void TQDataTable::setSort( const TQStringList& 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 TQSqlIndex contains
+ field names and their ordering (ASC or DESC); these are used to
+ compose the ORDER BY clause.
+
+ \sa sort()
+*/
+
+void TQDataTable::setSort( const TQSqlIndex& sort )
+{
+ d->cur.setSort( sort );
+}
+
+TQStringList TQDataTable::sort() const
+{
+ return d->cur.sort();
+}
+
+/*!
+ Returns the cursor used by the data table.
+*/
+
+TQSqlCursor* TQDataTable::sqlCursor() const
+{
+ return d->cur.cursor();
+}
+
+void TQDataTable::setConfirmEdits( bool confirm )
+{
+ d->dat.setConfirmEdits( confirm );
+}
+
+void TQDataTable::setConfirmInsert( bool confirm )
+{
+ d->dat.setConfirmInsert( confirm );
+}
+
+void TQDataTable::setConfirmUpdate( bool confirm )
+{
+ d->dat.setConfirmUpdate( confirm );
+}
+
+void TQDataTable::setConfirmDelete( bool confirm )
+{
+ d->dat.setConfirmDelete( confirm );
+}
+
+/*!
+ \property TQDataTable::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 TQDataTable::confirmEdits() const
+{
+ return ( d->dat.confirmEdits() );
+}
+
+/*!
+ \property TQDataTable::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 TQDataTable::confirmInsert() const
+{
+ return ( d->dat.confirmInsert() );
+}
+
+/*!
+ \property TQDataTable::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 TQDataTable::confirmUpdate() const
+{
+ return ( d->dat.confirmUpdate() );
+}
+
+/*!
+ \property TQDataTable::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 TQDataTable::confirmDelete() const
+{
+ return ( d->dat.confirmDelete() );
+}
+
+/*!
+ \property TQDataTable::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 TQDataTable::setConfirmCancels( bool confirm )
+{
+ d->dat.setConfirmCancels( confirm );
+}
+
+bool TQDataTable::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 TQDataTable cell.
+*/
+
+TQWidget * TQDataTable::createEditor( int , int col, bool initFromCell ) const
+{
+ if ( d->dat.mode() == TQSql::None )
+ return 0;
+
+ TQSqlEditorFactory * f = (d->editorFactory == 0) ?
+ TQSqlEditorFactory::defaultFactory() : d->editorFactory;
+
+ TQSqlPropertyMap * m = (d->propertyMap == 0) ?
+ TQSqlPropertyMap::defaultMap() : d->propertyMap;
+
+ TQWidget * 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 TQDataTable::eventFilter( TQObject *o, TQEvent *e )
+{
+ if ( d->cancelMode )
+ return TRUE;
+
+ int r = currentRow();
+ int c = currentColumn();
+
+ if ( d->dat.mode() != TQSql::None ) {
+ r = d->editRow;
+ c = d->editCol;
+ }
+
+ d->cancelInsert = FALSE;
+ d->cancelUpdate = FALSE;
+ switch ( e->type() ) {
+ case TQEvent::KeyPress: {
+ int conf = TQSql::Yes;
+ TQKeyEvent *ke = (TQKeyEvent*)e;
+ if ( ( ke->key() == Key_Tab || ke->key() == TQt::Key_BackTab )
+ && ke->state() & TQt::ControlButton )
+ return FALSE;
+
+ if ( ke->key() == Key_Escape && d->dat.mode() == TQSql::Insert ){
+ if ( confirmCancels() && !d->cancelMode ) {
+ d->cancelMode = TRUE;
+ conf = confirmCancel( TQSql::Insert );
+ d->cancelMode = FALSE;
+ }
+ if ( conf == TQSql::Yes ) {
+ d->cancelInsert = TRUE;
+ } else {
+ TQWidget *editorWidget = cellWidget( r, c );
+ if ( editorWidget ) {
+ editorWidget->setActiveWindow();
+ editorWidget->setFocus();
+ }
+ return TRUE;
+ }
+ }
+ if ( ke->key() == Key_Escape && d->dat.mode() == TQSql::Update ) {
+ if ( confirmCancels() && !d->cancelMode ) {
+ d->cancelMode = TRUE;
+ conf = confirmCancel( TQSql::Update );
+ d->cancelMode = FALSE;
+ }
+ if ( conf == TQSql::Yes ){
+ d->cancelUpdate = TRUE;
+ } else {
+ TQWidget *editorWidget = cellWidget( r, c );
+ if ( editorWidget ) {
+ editorWidget->setActiveWindow();
+ editorWidget->setFocus();
+ }
+ return TRUE;
+ }
+ }
+ if ( ke->key() == Key_Insert && d->dat.mode() == TQSql::None ) {
+ beginInsert();
+ return TRUE;
+ }
+ if ( ke->key() == Key_Delete && d->dat.mode() == TQSql::None ) {
+ deleteCurrent();
+ return TRUE;
+ }
+ if ( d->dat.mode() != TQSql::None ) {
+ if ( (ke->key() == Key_Tab) && (c < numCols() - 1) && (!isColumnReadOnly( c+1 ) || d->dat.mode() == TQSql::Insert) )
+ d->continuousEdit = TRUE;
+ else if ( (ke->key() == Key_BackTab) && (c > 0) && (!isColumnReadOnly( c-1 ) || d->dat.mode() == TQSql::Insert) )
+ d->continuousEdit = TRUE;
+ else
+ d->continuousEdit = FALSE;
+ }
+ TQSqlCursor * sql = sqlCursor();
+ if ( sql && sql->driver() &&
+ !sql->driver()->hasFeature( TQSqlDriver::QuerySize ) &&
+ ke->key() == Key_End && d->dat.mode() == TQSql::None ) {
+#ifndef QT_NO_CURSOR
+ TQApplication::setOverrideCursor( TQt::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
+ TQApplication::restoreOverrideCursor();
+#endif
+ return TRUE;
+ }
+ break;
+ }
+ case TQEvent::FocusOut: {
+ TQWidget *editorWidget = cellWidget( r, c );
+ repaintCell( currentRow(), currentColumn() );
+ if ( !d->cancelMode && editorWidget && o == editorWidget &&
+ ( d->dat.mode() == TQSql::Insert) && !d->continuousEdit) {
+ setCurrentCell( r, c );
+ d->cancelInsert = TRUE;
+ }
+ d->continuousEdit = FALSE;
+ break;
+ }
+ case TQEvent::FocusIn:
+ repaintCell( currentRow(), currentColumn() );
+ break;
+ default:
+ break;
+ }
+ return TQTable::eventFilter( o, e );
+}
+
+/*! \reimp */
+void TQDataTable::resizeEvent ( TQResizeEvent * e )
+{
+ if ( sqlCursor() &&
+ sqlCursor()->driver() &&
+ !sqlCursor()->driver()->hasFeature( TQSqlDriver::QuerySize ) )
+ loadNextPage();
+ TQTable::resizeEvent( e );
+}
+
+/*! \reimp */
+void TQDataTable::contentsContextMenuEvent( TQContextMenuEvent* e )
+{
+ TQTable::contentsContextMenuEvent( e );
+ if ( isEditing() && d->dat.mode() != TQSql::None )
+ endEdit( d->editRow, d->editCol, autoEdit(), FALSE );
+ if ( !sqlCursor() )
+ return;
+ if ( d->dat.mode() == TQSql::None ) {
+ if ( isReadOnly() )
+ return;
+ enum {
+ IdInsert,
+ IdUpdate,
+ IdDelete
+ };
+ TQGuardedPtr<TQPopupMenu> popup = new TQPopupMenu( 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 (TQPopupMenu*) 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 TQDataTable::contentsMousePressEvent( TQMouseEvent* e )
+{
+ TQTable::contentsMousePressEvent( e );
+}
+
+/*! \reimp */
+TQWidget* TQDataTable::beginEdit ( int row, int col, bool replace )
+{
+ d->editRow = -1;
+ d->editCol = -1;
+ if ( !sqlCursor() )
+ return 0;
+ if ( d->dat.mode() == TQSql::Insert && !sqlCursor()->canInsert() )
+ return 0;
+ if ( d->dat.mode() == TQSql::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 );
+ TQWidget* w = TQTable::beginEdit( row, col, replace );
+ setColumnReadOnly( col, fakeReadOnly );
+ return w;
+ }
+ if ( d->dat.mode() == TQSql::None && sqlCursor()->canUpdate() && sqlCursor()->primaryIndex().count() > 0 )
+ return beginUpdate( row, col, replace );
+ return 0;
+}
+
+/*! \reimp */
+void TQDataTable::endEdit( int row, int col, bool, bool )
+{
+ bool accept = autoEdit() && !d->cancelInsert && !d->cancelUpdate;
+
+ TQWidget *editor = cellWidget( row, col );
+ if ( !editor )
+ return;
+ if ( d->cancelMode )
+ return;
+ if ( d->dat.mode() != TQSql::None && d->editBuffer ) {
+ TQSqlPropertyMap * m = (d->propertyMap == 0) ?
+ TQSqlPropertyMap::defaultMap() : d->propertyMap;
+ d->editBuffer->setValue( indexOf( col ), m->property( editor ) );
+ clearCellWidget( row, col );
+ if ( !d->continuousEdit ) {
+ switch ( d->dat.mode() ) {
+ case TQSql::Insert:
+ if ( accept )
+ TQTimer::singleShot( 0, this, SLOT( doInsertCurrent() ) );
+ else
+ endInsert();
+ break;
+ case TQSql::Update:
+ if ( accept )
+ TQTimer::singleShot( 0, this, SLOT( doUpdateCurrent() ) );
+ else
+ endUpdate();
+ break;
+ default:
+ break;
+ }
+ }
+ } else {
+ setEditMode( NotEditing, -1, -1 );
+ }
+ if ( d->dat.mode() == TQSql::None )
+ viewport()->setFocus();
+ updateCell( row, col );
+ emit valueChanged( row, col );
+}
+
+/*! \internal */
+void TQDataTable::doInsertCurrent()
+{
+ insertCurrent();
+}
+
+/*! \internal */
+void TQDataTable::doUpdateCurrent()
+{
+ updateCurrent();
+ if ( d->dat.mode() == TQSql::None ) {
+ viewport()->setFocus();
+ }
+}
+
+/*! \reimp */
+void TQDataTable::activateNextCell()
+{
+// if ( d->dat.mode() == TQSql::None )
+// TQTable::activateNextCell();
+}
+
+/*! \internal
+*/
+
+void TQDataTable::endInsert()
+{
+ if ( d->dat.mode() != TQSql::Insert )
+ return;
+ d->dat.setMode( TQSql::None );
+ d->editBuffer = 0;
+ verticalHeader()->setLabel( d->editRow, TQString::number( d->editRow +1 ) );
+ d->editRow = -1;
+ d->editCol = -1;
+ d->insertRowLast = -1;
+ d->insertHeaderLabelLast = TQString::null;
+ setEditMode( NotEditing, -1, -1 );
+ setNumRows( d->insertPreRows );
+ d->insertPreRows = -1;
+ viewport()->setFocus();
+}
+
+/*! \internal
+*/
+
+void TQDataTable::endUpdate()
+{
+ d->dat.setMode( TQSql::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
+ TQSqlCursor::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 TQDataTable::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( TQSql::Insert );
+ int lastRow = row;
+ int lastY = contentsY() + visibleHeight();
+ for ( i = row; i < numRows() ; ++i ) {
+ TQRect 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 ( TQTable::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
+ TQSqlCursor::editBuffer()).
+
+ \a row and \a col refer to the row and column in the TQDataTable.
+
+ (\a replace is provided for reimplementors and reflects the API of
+ TQTable::beginEdit().)
+*/
+
+TQWidget* TQDataTable::beginUpdate ( int row, int col, bool replace )
+{
+ if ( !sqlCursor() || isReadOnly() || isColumnReadOnly( col ) )
+ return 0;
+ setCurrentCell( row, col );
+ d->dat.setMode( TQSql::Update );
+ if ( sqlCursor()->seek( row ) ) {
+ d->editBuffer = sqlCursor()->primeUpdate();
+ sqlCursor()->seek( currentRow() );
+ emit primeUpdate( d->editBuffer );
+ return TQTable::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 TQDataTable::insertCurrent()
+{
+ if ( d->dat.mode() != TQSql::Insert || ! numCols() )
+ return FALSE;
+ if ( !sqlCursor()->canInsert() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQDataTable::insertCurrent: insert not allowed for %s",
+ sqlCursor()->name().latin1() );
+#endif
+ endInsert();
+ return FALSE;
+ }
+ int b = 0;
+ int conf = TQSql::Yes;
+ if ( confirmEdits() || confirmInsert() )
+ conf = confirmEdit( TQSql::Insert );
+ switch ( conf ) {
+ case TQSql::Yes: {
+#ifndef QT_NO_CURSOR
+ TQApplication::setOverrideCursor( TQt::waitCursor );
+#endif
+ emit beforeInsert( d->editBuffer );
+ b = sqlCursor()->insert();
+#ifndef QT_NO_CURSOR
+ TQApplication::restoreOverrideCursor();
+#endif
+ if ( ( !b && !sqlCursor()->isActive() ) || !sqlCursor()->isActive() ) {
+ handleError( sqlCursor()->lastError() );
+ endInsert(); // cancel the insert if anything goes wrong
+ refresh();
+ } else {
+ endInsert();
+ refresh();
+ TQSqlIndex idx = sqlCursor()->primaryIndex();
+ findBuffer( idx, d->lastAt );
+ repaintContents( contentsX(), contentsY(), visibleWidth(), visibleHeight(), FALSE );
+ emit cursorChanged( TQSql::Insert );
+ }
+ break;
+ }
+ case TQSql::No:
+ endInsert();
+ break;
+ case TQSql::Cancel:
+ if ( TQTable::beginEdit( currentRow(), currentColumn(), FALSE ) )
+ setEditMode( Editing, currentRow(), currentColumn() );
+ break;
+ }
+ return ( b > 0 );
+}
+
+/*! \internal
+
+ Updates the row \a row.
+*/
+
+void TQDataTable::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 TQDataTable::updateCurrent()
+{
+ if ( d->dat.mode() != TQSql::Update )
+ return FALSE;
+ if ( sqlCursor()->primaryIndex().count() == 0 ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQDataTable::updateCurrent: no primary index for %s",
+ sqlCursor()->name().latin1() );
+#endif
+ endUpdate();
+ return FALSE;
+ }
+ if ( !sqlCursor()->canUpdate() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQDataTable::updateCurrent: updates not allowed for %s",
+ sqlCursor()->name().latin1() );
+#endif
+ endUpdate();
+ return FALSE;
+ }
+ int b = 0;
+ int conf = TQSql::Yes;
+ if ( confirmEdits() || confirmUpdate() )
+ conf = confirmEdit( TQSql::Update );
+ switch ( conf ) {
+ case TQSql::Yes: {
+#ifndef QT_NO_CURSOR
+ TQApplication::setOverrideCursor( TQt::waitCursor );
+#endif
+ emit beforeUpdate( d->editBuffer );
+ b = sqlCursor()->update();
+#ifndef QT_NO_CURSOR
+ TQApplication::restoreOverrideCursor();
+#endif
+ if ( ( !b && !sqlCursor()->isActive() ) || !sqlCursor()->isActive() ) {
+ handleError( sqlCursor()->lastError() );
+ endUpdate();
+ refresh();
+ setCurrentCell( d->editRow, d->editCol );
+ if ( TQTable::beginEdit( d->editRow, d->editCol, FALSE ) )
+ setEditMode( Editing, d->editRow, d->editCol );
+ } else {
+ emit cursorChanged( TQSql::Update );
+ refresh();
+ endUpdate();
+ }
+ break;
+ }
+ case TQSql::No:
+ endUpdate();
+ setEditMode( NotEditing, -1, -1 );
+ break;
+ case TQSql::Cancel:
+ setCurrentCell( d->editRow, d->editCol );
+ if ( TQTable::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 TQDataTable::deleteCurrent()
+{
+ if ( !sqlCursor() || isReadOnly() )
+ return FALSE;
+ if ( sqlCursor()->primaryIndex().count() == 0 ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQDataTable::deleteCurrent: no primary index %s",
+ sqlCursor()->name().latin1() );
+#endif
+ return FALSE;
+ }
+ if ( !sqlCursor()->canDelete() )
+ return FALSE;
+
+ int b = 0;
+ int conf = TQSql::Yes;
+ if ( confirmEdits() || confirmDelete() )
+ conf = confirmEdit( TQSql::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 TQSql::Yes:{
+#ifndef QT_NO_CURSOR
+ TQApplication::setOverrideCursor( TQt::waitCursor );
+#endif
+ sqlCursor()->primeDelete();
+ emit primeDelete( sqlCursor()->editBuffer() );
+ emit beforeDelete( sqlCursor()->editBuffer() );
+ b = sqlCursor()->del();
+#ifndef QT_NO_CURSOR
+ TQApplication::restoreOverrideCursor();
+#endif
+ if ( !b )
+ handleError( sqlCursor()->lastError() );
+ refresh();
+ emit cursorChanged( TQSql::Delete );
+ setCurrentCell( currentRow(), currentColumn() );
+ repaintContents( contentsX(), contentsY(), visibleWidth(), visibleHeight(), FALSE );
+ verticalHeader()->repaint(); // get rid of trailing garbage
+ }
+ break;
+ case TQSql::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.
+*/
+
+TQSql::Confirm TQDataTable::confirmEdit( TQSql::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.
+*/
+
+TQSql::Confirm TQDataTable::confirmCancel( TQSql::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 TQDataTable::find( const TQString & str, bool caseSensitive, bool backwards )
+{
+ if ( !sqlCursor() )
+ return;
+
+ TQSqlCursor * r = sqlCursor();
+ TQString 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
+ TQApplication::setOverrideCursor( TQt::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
+ TQApplication::restoreOverrideCursor();
+#endif
+}
+
+
+/*!
+ Resets the table so that it displays no data.
+
+ \sa setSqlCursor()
+*/
+
+void TQDataTable::reset()
+{
+ clearCellWidget( currentRow(), currentColumn() );
+ switch ( d->dat.mode() ) {
+ case TQSql::Insert:
+ endInsert();
+ break;
+ case TQSql::Update:
+ endUpdate();
+ break;
+ default:
+ break;
+ }
+ ensureVisible( 0, 0 );
+ verticalScrollBar()->setValue(0);
+ setNumRows(0);
+
+ d->haveAllRows = FALSE;
+ d->continuousEdit = FALSE;
+ d->dat.setMode( TQSql::None );
+ d->editRow = -1;
+ d->editCol = -1;
+ d->insertRowLast = -1;
+ d->insertHeaderLabelLast = TQString::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 TQDataTable::indexOf( uint i ) const
+{
+ TQDataTablePrivate::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 TQDataTable::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 TQDataTable::setAutoDelete( bool enable )
+{
+ d->cur.setAutoDelete( enable );
+}
+
+/*!
+ \property TQDataTable::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 TQDataTable::setAutoEdit( bool autoEdit )
+{
+ d->dat.setAutoEdit( autoEdit );
+}
+
+bool TQDataTable::autoEdit() const
+{
+ return d->dat.autoEdit();
+}
+
+/*!
+ \property TQDataTable::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 TQDataTable::setNullText( const TQString& nullText )
+{
+ d->nullTxt = nullText;
+ d->nullTxtChanged = TRUE;
+}
+
+TQString TQDataTable::nullText() const
+{
+ return d->nullTxt;
+}
+
+/*!
+ \property TQDataTable::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 TQDataTable::setTrueText( const TQString& trueText )
+{
+ d->trueTxt = trueText;
+}
+
+TQString TQDataTable::trueText() const
+{
+ return d->trueTxt;
+}
+
+/*!
+ \property TQDataTable::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 TQDataTable::setFalseText( const TQString& falseText )
+{
+ d->falseTxt = falseText;
+}
+
+TQString TQDataTable::falseText() const
+{
+ return d->falseTxt;
+}
+
+/*!
+ \property TQDataTable::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 TQt::LocalDate.
+*/
+
+void TQDataTable::setDateFormat( const DateFormat f )
+{
+ d->datefmt = f;
+}
+
+TQt::DateFormat TQDataTable::dateFormat() const
+{
+ return d->datefmt;
+}
+
+/*!
+ \property TQDataTable::numRows
+
+ \brief the number of rows in the table
+*/
+
+int TQDataTable::numRows() const
+{
+ return TQTable::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 TQDataTable::setNumRows ( int r )
+{
+ TQTable::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 TQDataTable::setNumCols ( int r )
+{
+ TQTable::setNumCols( r );
+}
+
+/*!
+ \property TQDataTable::numCols
+
+ \brief the number of columns in the table
+*/
+
+int TQDataTable::numCols() const
+{
+ return TQTable::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 TQString::null is
+ returned.
+*/
+
+TQString TQDataTable::text ( int row, int col ) const
+{
+ if ( !sqlCursor() )
+ return TQString::null;
+
+ TQString 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.
+*/
+
+TQVariant TQDataTable::value ( int row, int col ) const
+{
+ if ( !sqlCursor() )
+ return TQVariant();
+
+ TQVariant 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 TQDataTable::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() == TQSql::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 TQTable 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 TQDataTable::sliderPressed()
+{
+ disconnect( verticalScrollBar(), SIGNAL( valueChanged(int) ),
+ this, SLOT( loadNextPage() ) );
+}
+
+/*! \internal */
+void TQDataTable::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; TQDataTable always sorts
+ whole rows by the specified column.
+*/
+
+void TQDataTable::sortColumn ( int col, bool ascending,
+ bool )
+{
+ if ( sorting() ) {
+ if ( isEditing() && d->dat.mode() != TQSql::None )
+ endEdit( d->editRow, d->editCol, autoEdit(), FALSE );
+ if ( !sqlCursor() )
+ return;
+ TQSqlIndex lastSort = sqlCursor()->sort();
+ TQSqlIndex newSort( lastSort.cursorName(), "newSort" );
+ TQSqlField *field = sqlCursor()->field( indexOf( col ) );
+ if ( field )
+ newSort.append( *field );
+ newSort.setDescending( 0, !ascending );
+ horizontalHeader()->setSortIndicator( col, ascending );
+ setSort( newSort );
+ refresh();
+ }
+}
+
+/*! \reimp */
+void TQDataTable::columnClicked ( int col )
+{
+ if ( sorting() ) {
+ if ( !sqlCursor() )
+ return;
+ TQSqlIndex 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 TQDataTable::repaintCell( int row, int col )
+{
+ TQRect cg = cellGeometry( row, col );
+ TQRect re( TQPoint( cg.x() - 2, cg.y() - 2 ),
+ TQSize( 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 TQSql::isNull()
+*/
+
+void TQDataTable::paintCell( TQPainter * p, int row, int col, const TQRect & cr,
+ bool selected, const TQColorGroup &cg )
+{
+ TQTable::paintCell( p, row, col, cr, selected, cg ); // empty cell
+
+ if ( !sqlCursor() )
+ return;
+
+ p->setPen( selected ? cg.highlightedText() : cg.text() );
+ if ( d->dat.mode() != TQSql::None ) {
+ if ( row == d->editRow && d->editBuffer ) {
+ paintField( p, d->editBuffer->field( indexOf( col ) ), cr,
+ selected );
+ } else if ( row > d->editRow && d->dat.mode() == TQSql::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 TQDataTable::paintField( TQPainter * p, const TQSqlField* field,
+ const TQRect & 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 TQDataTable::fieldAlignment( const TQSqlField* /*field*/ )
+{
+ return TQt::AlignLeft | TQt::AlignVCenter; //## Reggie: add alignment to TQTable
+}
+
+
+/*!
+ 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 TQDataTable::setSize( TQSqlCursor* sql )
+{
+ // ### what are the connect/disconnect calls doing here!? move to refresh()
+ if ( sql->driver() && sql->driver()->hasFeature( TQSqlDriver::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() TQSqlDriver::nullText()
+*/
+
+void TQDataTable::setSqlCursor( TQSqlCursor* 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 TQDataTable::handleError( const TQSqlError& e )
+{
+ d->dat.handleError( this, e );
+}
+
+/*! \reimp
+ */
+
+void TQDataTable::keyPressEvent( TQKeyEvent* 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:
+ TQTable::keyPressEvent( e );
+ default:
+ return;
+ }
+}
+
+/*! \reimp
+*/
+
+void TQDataTable::resizeData ( int )
+{
+
+}
+
+/*! \reimp
+*/
+
+TQTableItem * TQDataTable::item ( int, int ) const
+{
+ return 0;
+}
+
+/*! \reimp
+*/
+
+void TQDataTable::setItem ( int , int , TQTableItem * )
+{
+
+}
+
+/*! \reimp
+*/
+
+void TQDataTable::clearCell ( int , int )
+{
+
+}
+
+/*! \reimp
+*/
+
+void TQDataTable::setPixmap ( int , int , const TQPixmap & )
+{
+
+}
+
+/*! \reimp */
+void TQDataTable::takeItem ( TQTableItem * )
+{
+
+}
+
+/*!
+ 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 TQDataTable takes ownership of this pointer, and will
+ delete it when it is no longer needed or when
+ installEditorFactory() is called again.
+
+ \sa TQSqlEditorFactory
+*/
+
+void TQDataTable::installEditorFactory( TQSqlEditorFactory * 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 TQDataTable takes ownership of this pointer, and will
+ delete it when it is no longer needed or when installPropertMap()
+ is called again.
+
+ \sa TQSqlPropertyMap
+*/
+
+void TQDataTable::installPropertyMap( TQSqlPropertyMap* m )
+{
+ if ( m ) {
+ delete d->propertyMap;
+ d->propertyMap = m;
+ }
+}
+
+/*! \internal
+
+ Sets the current selection to \a row, \a col.
+*/
+
+void TQDataTable::setCurrentSelection( int row, int )
+{
+ if ( !sqlCursor() )
+ return;
+ if ( row == d->lastAt )
+ return;
+ if ( !sqlCursor()->seek( row ) )
+ return;
+ d->lastAt = row;
+ emit currentChanged( sqlCursor() );
+}
+
+void TQDataTable::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.
+*/
+
+TQSqlRecord* TQDataTable::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 TQDataTable::sortAscending( int col )
+{
+ sortColumn( col, TRUE );
+}
+
+/*!
+ Sorts column \a col in descending order.
+
+ \sa setSorting()
+*/
+
+void TQDataTable::sortDescending( int col )
+{
+ sortColumn( col, FALSE );
+}
+
+/*!
+ \overload void TQDataTable::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 TQDataTable::refresh( TQDataTable::Refresh mode )
+{
+ TQSqlCursor* 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() ) {
+ TQSqlField* 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 ] ) {
+ TQTable::showColumn( i ); // ugly but necessary
+ TQTable::hideColumn( i );
+ } else {
+ TQTable::showColumn( i );
+ }
+ if ( d->fldWidth[ i ] > -1 )
+ TQTable::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( TQDataTable::RefreshData ).
+*/
+
+void TQDataTable::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 TQDataTable::findBuffer( const TQSqlIndex& idx, int atHint )
+{
+ TQSqlCursor* 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.
+*/
+TQString TQDataTable::fieldToString( const TQSqlField * field )
+{
+ TQString text;
+ if ( field->isNull() ) {
+ text = nullText();
+ } else {
+ TQVariant val = field->value();
+ switch ( val.type() ) {
+ case TQVariant::Bool:
+ text = val.toBool() ? d->trueTxt : d->falseTxt;
+ break;
+ case TQVariant::Date:
+ text = val.toDate().toString( d->datefmt );
+ break;
+ case TQVariant::Time:
+ text = val.toTime().toString( d->datefmt );
+ break;
+ case TQVariant::DateTime:
+ text = val.toDateTime().toString( d->datefmt );
+ break;
+ default:
+ text = val.toString();
+ break;
+ }
+ }
+ return text;
+}
+
+/*!
+ \reimp
+*/
+
+void TQDataTable::swapColumns( int col1, int col2, bool )
+{
+ TQString fld = d->fld[ col1 ];
+ TQString fldLabel = d->fldLabel[ col1 ];
+ TQIconSet 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 TQDataTable::drawContents( TQPainter * p, int cx, int cy, int cw, int ch )
+{
+ TQTable::drawContents( p, cx, cy, cw, ch );
+ if ( sqlCursor() && currentRow() >= 0 )
+ sqlCursor()->seek( currentRow() );
+}
+
+/*!
+ \reimp
+*/
+
+void TQDataTable::hideColumn( int col )
+{
+ d->fldHidden[col] = TRUE;
+ refresh( RefreshColumns );
+}
+
+/*!
+ \reimp
+*/
+
+void TQDataTable::showColumn( int col )
+{
+ d->fldHidden[col] = FALSE;
+ refresh( RefreshColumns );
+}
+
+/*!
+ \fn void TQDataTable::currentChanged( TQSqlRecord* 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 TQDataTable::primeInsert( TQSqlRecord* 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 TQDataTable::primeUpdate( TQSqlRecord* 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 TQDataTable::primeDelete( TQSqlRecord* 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 TQDataTable::beforeInsert( TQSqlRecord* 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 TQDataTable::beforeUpdate( TQSqlRecord* 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 TQDataTable::beforeDelete( TQSqlRecord* 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 TQDataTable::cursorChanged( TQSql::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/src/sql/qdatatable.h b/src/sql/qdatatable.h
new file mode 100644
index 000000000..7b789ca78
--- /dev/null
+++ b/src/sql/qdatatable.h
@@ -0,0 +1,244 @@
+/****************************************************************************
+**
+** Definition of TQDataTable class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQDATATABLE_H
+#define TQDATATABLE_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 TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL_VIEW_WIDGETS
+
+class TQPainter;
+class TQSqlField;
+class TQSqlPropertyMap;
+class TQDataTablePrivate;
+
+class TQM_EXPORT_SQL TQDataTable : public TQTable
+{
+ Q_OBJECT
+
+ Q_PROPERTY( TQString nullText READ nullText WRITE setNullText )
+ Q_PROPERTY( TQString trueText READ trueText WRITE setTrueText )
+ Q_PROPERTY( TQString 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( TQString filter READ filter WRITE setFilter )
+ Q_PROPERTY( TQStringList sort READ sort WRITE setSort )
+ Q_PROPERTY( int numCols READ numCols )
+ Q_PROPERTY( int numRows READ numRows )
+
+public:
+ TQDataTable ( TQWidget* parent=0, const char* name=0 );
+ TQDataTable ( TQSqlCursor* cursor, bool autoPopulate = FALSE, TQWidget* parent=0, const char* name=0 );
+ ~TQDataTable();
+
+ virtual void addColumn( const TQString& fieldName,
+ const TQString& label = TQString::null,
+ int width = -1,
+ const TQIconSet& iconset = TQIconSet() );
+ virtual void removeColumn( uint col );
+ virtual void setColumn( uint col, const TQString& fieldName,
+ const TQString& label = TQString::null,
+ int width = -1,
+ const TQIconSet& iconset = TQIconSet() );
+
+ TQString nullText() const;
+ TQString trueText() const;
+ TQString 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;
+ TQString filter() const;
+ TQStringList sort() const;
+
+ virtual void setSqlCursor( TQSqlCursor* cursor = 0,
+ bool autoPopulate = FALSE, bool autoDelete = FALSE );
+ TQSqlCursor* sqlCursor() const;
+
+ virtual void setNullText( const TQString& nullText );
+ virtual void setTrueText( const TQString& trueText );
+ virtual void setFalseText( const TQString& 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 TQString& filter );
+ virtual void setSort( const TQStringList& sort );
+ virtual void setSort( const TQSqlIndex& sort );
+
+ enum Refresh {
+ RefreshData = 1,
+ RefreshColumns = 2,
+ RefreshAll = 3
+ };
+ void refresh( Refresh mode );
+ void sortColumn ( int col, bool ascending = TRUE,
+ bool wholeRows = FALSE );
+ TQString text ( int row, int col ) const;
+ TQVariant value ( int row, int col ) const;
+ TQSqlRecord* currentRecord() const;
+
+ void installEditorFactory( TQSqlEditorFactory * f );
+ void installPropertyMap( TQSqlPropertyMap* m );
+
+ int numCols() const;
+ int numRows() const;
+ void setNumCols( int c );
+ void setNumRows ( int r );
+ bool findBuffer( const TQSqlIndex& idx, int atHint = 0 );
+
+ void hideColumn( int col );
+ void showColumn( int col );
+signals:
+ void currentChanged( TQSqlRecord* record );
+ void primeInsert( TQSqlRecord* buf );
+ void primeUpdate( TQSqlRecord* buf );
+ void primeDelete( TQSqlRecord* buf );
+ void beforeInsert( TQSqlRecord* buf );
+ void beforeUpdate( TQSqlRecord* buf );
+ void beforeDelete( TQSqlRecord* buf );
+ void cursorChanged( TQSql::Op mode );
+
+public slots:
+ virtual void find( const TQString & 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 TQSql::Confirm confirmEdit( TQSql::Op m );
+ virtual TQSql::Confirm confirmCancel( TQSql::Op m );
+
+ virtual void handleError( const TQSqlError& e );
+
+ virtual bool beginInsert();
+ virtual TQWidget* beginUpdate ( int row, int col, bool replace );
+
+ bool eventFilter( TQObject *o, TQEvent *e );
+ void keyPressEvent( TQKeyEvent* );
+ void resizeEvent ( TQResizeEvent * );
+ void contentsMousePressEvent( TQMouseEvent* e );
+ void contentsContextMenuEvent( TQContextMenuEvent* e );
+ void endEdit( int row, int col, bool accept, bool replace );
+ TQWidget * 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( TQSqlCursor* sql );
+ void repaintCell( int row, int col );
+ void paintCell ( TQPainter * p, int row, int col, const TQRect & cr,
+ bool selected, const TQColorGroup &cg );
+ virtual void paintField( TQPainter * p, const TQSqlField* field, const TQRect & cr,
+ bool selected );
+ void drawContents( TQPainter * p, int cx, int cy, int cw, int ch );
+ virtual int fieldAlignment( const TQSqlField* field );
+ void columnClicked ( int col );
+ void resizeData ( int len );
+
+ TQTableItem * item ( int row, int col ) const;
+ void setItem ( int row, int col, TQTableItem * item );
+ void clearCell ( int row, int col ) ;
+ void setPixmap ( int row, int col, const TQPixmap & pix );
+ void takeItem ( TQTableItem * i );
+
+private slots:
+ void loadNextPage();
+ void setCurrentSelection( int row, int col );
+ void updateCurrentSelection();
+ void sliderPressed();
+ void sliderReleased();
+ void doInsertCurrent();
+ void doUpdateCurrent();
+
+private:
+ TQString fieldToString( const TQSqlField * field );
+ void init();
+ TQWidget* beginEdit ( int row, int col, bool replace );
+ void updateRow( int row );
+ void endInsert();
+ void endUpdate();
+ TQDataTablePrivate* d;
+
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ TQDataTable( const TQDataTable & );
+ TQDataTable &operator=( const TQDataTable & );
+#endif
+};
+
+#endif
+#endif
diff --git a/src/sql/qdataview.cpp b/src/sql/qdataview.cpp
new file mode 100644
index 000000000..1a73dc6f5
--- /dev/null
+++ b/src/sql/qdataview.cpp
@@ -0,0 +1,208 @@
+/****************************************************************************
+**
+** Implementation of TQDataView class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQDataViewPrivate
+{
+public:
+ TQDataViewPrivate() {}
+ TQSqlFormManager frm;
+};
+
+
+/*!
+ \class TQDataView qdataview.h
+ \brief The TQDataView 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 TQDataView does not support editing it uses
+ less resources than a TQDataBrowser. 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
+ TQDataBrowser; if you want a table-based presentation of your data
+ use TQDataTable.
+
+ The form is associated with the data view with setForm() and the
+ record is associated with setRecord(). You can also pass a
+ TQSqlRecord 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.
+*/
+
+TQDataView::TQDataView( TQWidget *parent, const char *name, WFlags fl )
+ : TQWidget( parent, name, fl )
+{
+ d = new TQDataViewPrivate();
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQDataView::~TQDataView()
+{
+ 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 TQDataView::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 TQDataView::setForm( TQSqlForm* form )
+{
+ d->frm.setForm( form );
+}
+
+
+/*!
+ Returns the default form used by the data view, or 0 if there is
+ none.
+
+ \sa setForm()
+*/
+
+TQSqlForm* TQDataView::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 TQDataView::setRecord( TQSqlRecord* record )
+{
+ d->frm.setRecord( record );
+}
+
+
+/*!
+ Returns the default record used by the data view, or 0 if there is
+ none.
+
+ \sa setRecord()
+*/
+
+TQSqlRecord* TQDataView::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 TQDataView::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 TQDataView::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 TQDataView::refresh( TQSqlRecord* buf )
+{
+ if ( buf && buf != record() )
+ setRecord( buf );
+ readFields();
+}
+
+#endif
diff --git a/src/sql/qdataview.h b/src/sql/qdataview.h
new file mode 100644
index 000000000..e45227b2f
--- /dev/null
+++ b/src/sql/qdataview.h
@@ -0,0 +1,90 @@
+/****************************************************************************
+**
+** Definition of TQDataView class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQDATAVIEW_H
+#define TQDATAVIEW_H
+
+#ifndef QT_H
+#include "qwidget.h"
+#endif // QT_H
+
+#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL )
+#define TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL_VIEW_WIDGETS
+
+class TQSqlForm;
+class TQSqlRecord;
+class TQDataViewPrivate;
+
+class TQM_EXPORT_SQL TQDataView : public TQWidget
+{
+ Q_OBJECT
+
+public:
+ TQDataView( TQWidget* parent=0, const char* name=0, WFlags fl = 0 );
+ ~TQDataView();
+
+ virtual void setForm( TQSqlForm* form );
+ TQSqlForm* form();
+ virtual void setRecord( TQSqlRecord* record );
+ TQSqlRecord* record();
+
+public slots:
+ virtual void refresh( TQSqlRecord* buf );
+ virtual void readFields();
+ virtual void writeFields();
+ virtual void clearValues();
+
+private:
+ TQDataViewPrivate* d;
+
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ TQDataView( const TQDataView & );
+ TQDataView &operator=( const TQDataView & );
+#endif
+};
+
+
+#endif
+#endif
diff --git a/src/sql/qeditorfactory.cpp b/src/sql/qeditorfactory.cpp
new file mode 100644
index 000000000..dc2c4f62f
--- /dev/null
+++ b/src/sql/qeditorfactory.cpp
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Implementation of TQEditorFactory class
+**
+** Created : 2000-11-17
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQEditorFactory qeditorfactory.h
+ \brief The TQEditorFactory class is used to create editor widgets
+ for TQVariant data types.
+
+ \ingroup database
+ \module sql
+
+ Each editor factory provides the createEditor() function which
+ given a TQVariant will create and return a TQWidget that can edit
+ that TQVariant. For example if you have a TQVariant::String type, a
+ TQLineEdit would be the default editor returned, whereas a
+ TQVariant::Int's default editor would be a TQSpinBox.
+
+ If you want to create different editors for fields with the same
+ data type, subclass TQEditorFactory and reimplement the
+ createEditor() function.
+*/
+
+/*!
+ Constructs an editor factory with parent \a parent, called \a name.
+*/
+
+TQEditorFactory::TQEditorFactory ( TQObject * parent, const char * name )
+ : TQObject( parent, name )
+{
+
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQEditorFactory::~TQEditorFactory()
+{
+
+}
+
+static TQEditorFactory * defaultfactory = 0;
+static TQCleanupHandler< TQEditorFactory > q_cleanup_editor_factory;
+
+/*!
+ Returns an instance of a default editor factory.
+*/
+
+TQEditorFactory * TQEditorFactory::defaultFactory()
+{
+ if( defaultfactory == 0 ){
+ defaultfactory = new TQEditorFactory();
+ q_cleanup_editor_factory.add( &defaultfactory );
+ }
+
+ return defaultfactory;
+}
+
+/*!
+ Replaces the default editor factory with \a factory.
+ \e{TQEditorFactory takes ownership of factory, and destroys it
+ when it is no longer needed.}
+*/
+
+void TQEditorFactory::installDefaultFactory( TQEditorFactory * 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 TQVariant \a v.
+ If the TQVariant is invalid, 0 is returned. The \a parent is passed
+ to the appropriate editor's constructor.
+*/
+
+TQWidget * TQEditorFactory::createEditor( TQWidget * parent, const TQVariant & v )
+{
+ TQWidget * w = 0;
+ switch( v.type() ){
+ case TQVariant::Invalid:
+ w = 0;
+ break;
+ case TQVariant::Bool:
+ w = new TQComboBox( parent, "qt_editor_bool" );
+ ((TQComboBox *) w)->insertItem( "False" );
+ ((TQComboBox *) w)->insertItem( "True" );
+ break;
+ case TQVariant::UInt:
+ w = new TQSpinBox( 0, 999999, 1, parent, "qt_editor_spinbox" );
+ break;
+ case TQVariant::Int:
+ w = new TQSpinBox( -999999, 999999, 1, parent, "qt_editor_int" );
+ break;
+ case TQVariant::String:
+ case TQVariant::CString:
+ case TQVariant::Double:
+ w = new TQLineEdit( parent, "qt_editor_double" );
+ ((TQLineEdit*)w)->setFrame( FALSE );
+ break;
+ case TQVariant::Date:
+ w = new TQDateEdit( parent, "qt_editor_date" );
+ break;
+ case TQVariant::Time:
+ w = new TQTimeEdit( parent, "qt_editor_time" );
+ break;
+ case TQVariant::DateTime:
+ w = new TQDateTimeEdit( parent, "qt_editor_datetime" );
+ break;
+#ifndef QT_NO_LABEL
+ case TQVariant::Pixmap:
+ w = new TQLabel( parent, "qt_editor_pixmap" );
+ break;
+#endif
+ case TQVariant::Palette:
+ case TQVariant::ColorGroup:
+ case TQVariant::Color:
+ case TQVariant::Font:
+ case TQVariant::Brush:
+ case TQVariant::Bitmap:
+ case TQVariant::Cursor:
+ case TQVariant::Map:
+ case TQVariant::StringList:
+ case TQVariant::Rect:
+ case TQVariant::Size:
+ case TQVariant::IconSet:
+ case TQVariant::Point:
+ case TQVariant::PointArray:
+ case TQVariant::Region:
+ case TQVariant::SizePolicy:
+ case TQVariant::ByteArray:
+ default:
+ w = new TQWidget( parent, "qt_editor_default" );
+ break;
+ }
+ return w;
+}
+#endif // QT_NO_SQL
diff --git a/src/sql/qeditorfactory.h b/src/sql/qeditorfactory.h
new file mode 100644
index 000000000..7f3428f77
--- /dev/null
+++ b/src/sql/qeditorfactory.h
@@ -0,0 +1,76 @@
+/****************************************************************************
+**
+** Definition of TQEditorFactory class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQEDITORFACTORY_H
+#define TQEDITORFACTORY_H
+
+#ifndef QT_H
+#include "qobject.h"
+#include "qvariant.h"
+#endif // QT_H
+
+#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL )
+#define TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL_EDIT_WIDGETS
+
+class TQM_EXPORT_SQL TQEditorFactory : public TQObject
+{
+public:
+ TQEditorFactory ( TQObject * parent = 0, const char * name = 0 );
+ ~TQEditorFactory();
+
+ virtual TQWidget * createEditor( TQWidget * parent, const TQVariant & v );
+
+ static TQEditorFactory * defaultFactory();
+ static void installDefaultFactory( TQEditorFactory * factory);
+
+private:
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ TQEditorFactory( const TQEditorFactory & );
+ TQEditorFactory &operator=( const TQEditorFactory & );
+#endif
+};
+
+#endif // QT_NO_SQL
+#endif // TQEDITORFACTORY_H
diff --git a/src/sql/qsql.cpp b/src/sql/qsql.cpp
new file mode 100644
index 000000000..c2932fbe0
--- /dev/null
+++ b/src/sql/qsql.cpp
@@ -0,0 +1,114 @@
+/****************************************************************************
+**
+** Implementation of TQSql class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSql qsql.h
+ \brief The TQSql class is a namespace for TQt SQL identifiers that
+ need to be global-like.
+
+ \ingroup database
+ \mainclass
+ \module sql
+
+ Normally, you can ignore this class. Several TQt SQL classes
+ inherit it, so all the identifiers in the TQt SQL namespace are
+ visible without qualification.
+*/
+
+/*!
+ \enum TQSql::Confirm
+
+ This enum type describes edit confirmations.
+
+ \value Yes
+ \value No
+ \value Cancel
+*/
+
+/*!
+ \enum TQSql::Op
+
+ This enum type describes edit operations.
+
+ \value None
+ \value Insert
+ \value Update
+ \value Delete
+*/
+
+
+/*!
+ \enum TQSql::Location
+
+ This enum type describes SQL navigation locations.
+
+ \value BeforeFirst
+ \value AfterLast
+*/
+
+/*!
+ \enum TQSql::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 TQSql::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 TQSql::TQSql()
+
+ Constructs a TQt SQL namespace class
+*/
diff --git a/src/sql/qsql.h b/src/sql/qsql.h
new file mode 100644
index 000000000..3fcbfc7f4
--- /dev/null
+++ b/src/sql/qsql.h
@@ -0,0 +1,100 @@
+/****************************************************************************
+**
+** Definition of TQSql class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQL_H
+#define TQSQL_H
+
+#ifndef QT_H
+#include "qglobal.h"
+#endif // QT_H
+
+#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL )
+#define TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL
+
+class TQM_EXPORT_SQL TQSql
+{
+public:
+ TQSql() {}
+ 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)
+ TQSql( const TQSql & );
+ TQSql &operator=( const TQSql & );
+#endif
+
+};
+
+#endif
+#endif
diff --git a/src/sql/qsqlcursor.cpp b/src/sql/qsqlcursor.cpp
new file mode 100644
index 000000000..5ec8b754a
--- /dev/null
+++ b/src/sql/qsqlcursor.cpp
@@ -0,0 +1,1549 @@
+/****************************************************************************
+**
+** Implementation of TQSqlCursor class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlCursorPrivate
+{
+public:
+
+ TQSqlCursorPrivate( const TQString& name, TQSqlDatabase* sdb )
+ : lastAt( TQSql::BeforeFirst ), nm( name ), srt( name ), md( 0 ), db( sdb ), q( 0 )
+ {}
+ ~TQSqlCursorPrivate()
+ {
+ delete q;
+ }
+
+ TQSqlQuery* query()
+ {
+ if ( !q )
+ q = new TQSqlQuery( 0, db );
+ return q;
+ }
+
+ int lastAt;
+ TQString nm; //name
+ TQSqlIndex srt; //sort
+ TQString ftr; //filter
+ int md; //mode
+ TQSqlIndex priIndx; //primary index
+ TQSqlRecord editBuffer;
+ // the primary index as it was before the user changed the values in editBuffer
+ TQString editIndex;
+ TQSqlRecordInfo infoBuffer;
+ TQSqlDatabase* db;
+ TQSqlQuery* q;
+};
+
+TQString qOrderByClause( const TQSqlIndex & i, const TQString& prefix = TQString::null )
+{
+ TQString str;
+ int k = i.count();
+ if( k == 0 ) return TQString::null;
+ str = " order by " + i.toString( prefix );
+ return str;
+}
+
+TQString qWhereClause( const TQString& prefix, TQSqlField* field, const TQSqlDriver* driver )
+{
+ TQString f;
+ if ( field && driver ) {
+ f = ( prefix.length() > 0 ? prefix + TQString(".") : TQString::null ) + field->name();
+ if ( field->isNull() ) {
+ f += " IS NULL";
+ } else {
+ f += " = " + driver->formatValue( field );
+ }
+ }
+ return f;
+}
+
+TQString qWhereClause( TQSqlRecord* rec, const TQString& prefix, const TQString& sep,
+ const TQSqlDriver* driver )
+{
+ static TQString blank( " " );
+ TQString filter;
+ bool separator = FALSE;
+ for ( uint j = 0; j < rec->count(); ++j ) {
+ TQSqlField* 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 TQSqlCursor qsqlcursor.h
+ \brief The TQSqlCursor class provides browsing and editing of SQL
+ tables and views.
+
+ \ingroup database
+ \module sql
+
+ A TQSqlCursor is a database record (see \l TQSqlRecord) that
+ corresponds to a table or view within an SQL database (see \l
+ TQSqlDatabase). 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 TQSqlCursor
+ \printline TQSqlCursor
+ \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()
+ retquire 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.
+
+ TQSqlCursor 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. TQSqlCursor
+ generates SQL statements which are sent to the database engine;
+ you can control which fields are included in these statements
+ using setGenerated().
+
+ Note that TQSqlCursor does not inherit from TQObject. This means
+ that you are responsible for destroying instances of this class
+ yourself. However if you create a TQSqlCursor and use it in a
+ \l TQDataTable, \l TQDataBrowser or a \l TQDataView these classes will
+ usually take ownership of the cursor and destroy it when they
+ don't need it anymore. The documentation for TQDataTable,
+ TQDataBrowser and TQDataView explicitly states which calls take
+ ownership of the cursor.
+*/
+
+/*!
+ \enum TQSqlCursor::Mode
+
+ This enum type describes how TQSqlCursor 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 TQSqlCursor::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()
+*/
+
+TQSqlCursor::TQSqlCursor( const TQString & name, bool autopopulate, TQSqlDatabase* db )
+ : TQSqlRecord(), TQSqlQuery( TQString::null, db )
+{
+ d = new TQSqlCursorPrivate( name, db );
+ setMode( Writable );
+ if ( !d->nm.isNull() )
+ setName( d->nm, autopopulate );
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+
+TQSqlCursor::TQSqlCursor( const TQSqlCursor & other )
+ : TQSqlRecord( other ), TQSqlQuery( other )
+{
+ d = new TQSqlCursorPrivate( 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.
+*/
+
+TQSqlCursor::~TQSqlCursor()
+{
+ delete d;
+}
+
+/*!
+ Sets the cursor equal to \a other.
+*/
+
+TQSqlCursor& TQSqlCursor::operator=( const TQSqlCursor& other )
+{
+ TQSqlRecord::operator=( other );
+ TQSqlQuery::operator=( other );
+ delete d;
+ d = new TQSqlCursorPrivate( 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 TQSqlCursor::setSort( const TQSqlIndex& sort )
+{
+ d->srt = sort;
+}
+
+/*!
+ Returns the current sort, or an empty index if there is no current
+ sort.
+*/
+TQSqlIndex TQSqlCursor::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 TQSqlCursor::setFilter( const TQString& filter )
+{
+ d->ftr = filter;
+}
+
+/*!
+ Returns the current filter, or an empty string if there is no
+ current filter.
+*/
+TQString TQSqlCursor::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 TQSqlCursor constructor documentation for
+ more information.
+*/
+void TQSqlCursor::setName( const TQString& 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("TQSqlCursor::setName: unable to build record, does '%s' exist?", name.latin1() );
+#endif
+ }
+}
+
+/*!
+ Returns the name of the cursor.
+*/
+
+TQString TQSqlCursor::name() const
+{
+ return d->nm;
+}
+
+/*! \reimp
+*/
+
+TQString TQSqlCursor::toString( const TQString& prefix, const TQString& sep ) const
+{
+ TQString pflist;
+ TQString pfix = prefix.isEmpty() ? TQString::null : prefix + ".";
+ bool comma = FALSE;
+
+ for ( uint i = 0; i < count(); ++i ) {
+ const TQString fname = fieldName( i );
+ if ( isGenerated( i ) ) {
+ if( comma )
+ pflist += sep + " ";
+ pflist += pfix + fname;
+ comma = TRUE;
+ }
+ }
+ return pflist;
+}
+
+/*!
+ \internal
+
+ Assigns the record \a list.
+
+*/
+TQSqlRecord & TQSqlCursor::operator=( const TQSqlRecord & list )
+{
+ return TQSqlRecord::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 TQSqlCursor::append( const TQSqlFieldInfo& fieldInfo )
+{
+ d->editBuffer.append( fieldInfo.toField() );
+ d->editBuffer.setGenerated( d->editBuffer.count() - 1, fieldInfo.isGenerated() );
+ d->infoBuffer.append( fieldInfo );
+ TQSqlRecord::append( fieldInfo.toField() );
+ TQSqlRecord::setGenerated( TQSqlRecord::count() - 1, fieldInfo.isGenerated() );
+}
+
+/*!
+ Removes all fields from the cursor. Note that all references to
+ the cursor edit buffer become invalidated.
+*/
+void TQSqlCursor::clear()
+{
+ d->editBuffer.clear();
+ d->infoBuffer.clear();
+ TQSqlRecord::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 TQSqlCursor::insert( int pos, const TQSqlFieldInfo& fieldInfo )
+{
+ d->editBuffer.insert( pos, fieldInfo.toField() );
+ d->editBuffer.setGenerated( pos, fieldInfo.isGenerated() );
+ d->infoBuffer[ pos ] = fieldInfo;
+ TQSqlRecord::insert( pos, fieldInfo.toField() );
+ TQSqlRecord::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 TQSqlCursor::remove( int pos )
+{
+ d->editBuffer.remove( pos );
+ d->infoBuffer[ pos ] = TQSqlFieldInfo();
+ TQSqlRecord::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 TQSqlCursor::setGenerated( const TQString& name, bool generated )
+{
+ int pos = position( name );
+ if ( pos == -1 )
+ return;
+ TQSqlRecord::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 TQSqlCursor::setGenerated( int i, bool generated )
+{
+ if ( i < 0 || i >= (int)d->infoBuffer.count() )
+ return;
+ TQSqlRecord::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.
+*/
+
+TQSqlIndex TQSqlCursor::primaryIndex( bool setFromCursor ) const
+{
+ if ( setFromCursor ) {
+ for ( uint i = 0; i < d->priIndx.count(); ++i ) {
+ const TQString 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 TQSqlCursor::setPrimaryIndex( const TQSqlIndex& 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 TQSqlIndex
+*/
+
+TQSqlIndex TQSqlCursor::index( const TQStringList& fieldNames ) const
+{
+ TQSqlIndex idx;
+ for ( TQStringList::ConstIterator it = fieldNames.begin(); it != fieldNames.end(); ++it ) {
+ const TQSqlField* 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.
+*/
+
+TQSqlIndex TQSqlCursor::index( const TQString& fieldName ) const
+{
+ TQStringList fl( fieldName );
+ return index( fl );
+}
+
+/*!
+ \overload
+
+ Returns an index based on \a fieldName.
+*/
+
+TQSqlIndex TQSqlCursor::index( const char* fieldName ) const
+{
+ return index( TQStringList( TQString( 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
+ TQSqlCursor 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
+ TQSqlCursor 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 TQSqlCursor::select( const TQString & filter, const TQSqlIndex & sort )
+{
+ TQString fieldList = toString( d->nm );
+ if ( fieldList.isEmpty() )
+ return FALSE;
+ TQString str= "select " + fieldList;
+ str += " from " + d->nm;
+ if ( !filter.isEmpty() ) {
+ d->ftr = filter;
+ str += " where " + filter;
+ } else
+ d->ftr = TQString::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 TQSqlCursor::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 TQSqlCursor::select( const TQSqlIndex& 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
+ TQSqlCursor cur( "Employee" );
+ TQSqlIndex 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 TQSqlIndex, 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 TQSqlCursor::select( const TQSqlIndex & filter, const TQSqlIndex & 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 TQSqlCursor::Mode values. The default mode for a
+ cursor is \c TQSqlCursor::Writable.
+
+ \code
+ TQSqlCursor cur( "Employee" );
+ cur.setMode( TQSqlCursor::Writable ); // allow insert/update/delete
+ ...
+ cur.setMode( TQSqlCursor::Insert | TQSqlCursor::Update ); // allow inserts and updates only
+ ...
+ cur.setMode( TQSqlCursor::ReadOnly ); // no inserts/updates/deletes allowed
+
+ \endcode
+*/
+
+void TQSqlCursor::setMode( int mode )
+{
+ d->md = mode;
+}
+
+/*!
+ Returns the current cursor mode.
+
+ \sa setMode()
+*/
+
+int TQSqlCursor::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 TQVariant). Calculated
+ fields do not appear in generated SQL statements sent to the
+ database.
+
+ \sa calculateField() TQSqlRecord::setGenerated()
+*/
+
+void TQSqlCursor::setCalculated( const TQString& 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 TQSqlCursor::isCalculated( const TQString& 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() TQVariant
+*/
+
+void TQSqlCursor::setTrimmed( const TQString& 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 TQSqlCursor::isTrimmed( const TQString& 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 TQSqlCursor::isReadOnly() const
+{
+ return d->md == 0;
+}
+
+/*!
+ Returns TRUE if the cursor will perform inserts; otherwise returns
+ FALSE.
+
+ \sa setMode()
+*/
+
+bool TQSqlCursor::canInsert() const
+{
+ return ( ( d->md & Insert ) == Insert ) ;
+}
+
+
+/*!
+ Returns TRUE if the cursor will perform updates; otherwise returns
+ FALSE.
+
+ \sa setMode()
+*/
+
+bool TQSqlCursor::canUpdate() const
+{
+ return ( ( d->md & Update ) == Update ) ;
+}
+
+/*!
+ Returns TRUE if the cursor will perform deletes; otherwise returns
+ FALSE.
+
+ \sa setMode()
+*/
+
+bool TQSqlCursor::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.
+*/
+
+TQString TQSqlCursor::toString( const TQString& prefix, TQSqlField* field, const TQString& fieldSep ) const
+{
+ TQString f;
+ if ( field && driver() ) {
+ f = ( prefix.length() > 0 ? prefix + TQString(".") : TQString::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.
+*/
+
+TQString TQSqlCursor::toString( TQSqlRecord* rec, const TQString& prefix, const TQString& fieldSep,
+ const TQString& sep ) const
+{
+ static TQString blank( " " );
+ TQString filter;
+ bool separator = FALSE;
+ for ( uint j = 0; j < count(); ++j ) {
+ TQSqlField* 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.
+*/
+
+TQString TQSqlCursor::toString( const TQSqlIndex& i, TQSqlRecord* rec, const TQString& prefix,
+ const TQString& fieldSep, const TQString& sep ) const
+{
+ TQString filter;
+ bool separator = FALSE;
+ for( uint j = 0; j < i.count(); ++j ){
+ if ( rec->isGenerated( j ) ) {
+ if( separator ) {
+ filter += " " + sep + " " ;
+ }
+ TQString fn = i.fieldName( j );
+ TQSqlField* 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 atquired 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 TQSqlCursor::insert( bool invalidate )
+{
+ if ( ( d->md & Insert ) != Insert || !driver() )
+ return FALSE;
+ int k = d->editBuffer.count();
+ if ( k == 0 )
+ return 0;
+
+ TQString fList;
+ TQString vList;
+ bool comma = FALSE;
+ // use a prepared query if the driver supports it
+ if ( driver()->hasFeature( TQSqlDriver::PreparedQueries ) ) {
+ int cnt = 0;
+ bool oraStyle = driver()->hasFeature( TQSqlDriver::NamedPlaceholders );
+ for( int j = 0; j < k; ++j ) {
+ TQSqlField* f = d->editBuffer.field( j );
+ if ( d->editBuffer.isGenerated( j ) ) {
+ if ( comma ) {
+ fList += ",";
+ vList += ",";
+ }
+ fList += f->name();
+ vList += (oraStyle == TRUE) ? ":f" + TQString::number(cnt) : TQString("?");
+ cnt++;
+ comma = TRUE;
+ }
+ }
+ if ( !comma ) {
+ return 0;
+ }
+ TQString 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 ) {
+ TQSqlField* 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;
+ }
+ TQString 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()
+*/
+
+TQSqlRecord* TQSqlCursor::editBuffer( bool copy )
+{
+ if ( copy ) {
+ for(uint i = 0; i < d->editBuffer.count(); i++) {
+ if ( TQSqlRecord::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()
+*/
+
+TQSqlRecord* TQSqlCursor::primeUpdate()
+{
+ // memorize the primary keys as they were before the user changed the values in editBuffer
+ TQSqlRecord* buf = editBuffer( TRUE );
+ TQSqlIndex 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()
+*/
+
+TQSqlRecord* TQSqlCursor::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()
+*/
+
+TQSqlRecord* TQSqlCursor::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 actquired 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 TQSqlCursor::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 TQSqlCursor::update( const TQString & 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( TQSqlDriver::PreparedQueries ) ) {
+ TQString fList;
+ bool comma = FALSE;
+ int cnt = 0;
+ bool oraStyle = driver()->hasFeature( TQSqlDriver::NamedPlaceholders );
+ for( int j = 0; j < k; ++j ) {
+ TQSqlField* f = d->editBuffer.field( j );
+ if ( d->editBuffer.isGenerated( j ) ) {
+ if ( comma ) {
+ fList += ",";
+ }
+ fList += f->name() + " = " + (oraStyle == TRUE ? ":f" + TQString::number(cnt) : TQString("?"));
+ cnt++;
+ comma = TRUE;
+ }
+ }
+ if ( !comma ) {
+ return 0;
+ }
+ TQString str = "update " + name() + " set " + fList;
+ if ( filter.length() ) {
+ str+= " where " + filter;
+ }
+ return applyPrepared( str, invalidate );
+ } else {
+ TQString str = "update " + name();
+ str += " set " + toString( &d->editBuffer, TQString::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 TQSqlCursor::del( bool invalidate )
+{
+ TQSqlIndex 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 TQSqlCursor::del( const TQString & filter, bool invalidate )
+{
+ if ( ( d->md & Delete ) != Delete )
+ return 0;
+ int k = count();
+ if( k == 0 ) return 0;
+ TQString str = "delete from " + name();
+ if ( filter.length() )
+ str+= " where " + filter;
+ return apply( str, invalidate );
+}
+
+/*
+ \internal
+*/
+
+int TQSqlCursor::apply( const TQString& q, bool invalidate )
+{
+ int ar = 0;
+ if ( invalidate ) {
+ if ( exec( q ) )
+ ar = numRowsAffected();
+ } else if ( driver() ) {
+ TQSqlQuery* sql = d->query();
+ if ( sql && sql->exec( q ) )
+ ar = sql->numRowsAffected();
+ }
+ return ar;
+}
+
+/*
+ \internal
+*/
+
+int TQSqlCursor::applyPrepared( const TQString& q, bool invalidate )
+{
+ int ar = 0;
+ TQSqlQuery* sql = 0;
+
+ if ( invalidate ) {
+ sql = (TQSqlQuery*)this;
+ d->lastAt = TQSql::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 TQSqlField* 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 TQSqlCursor::exec( const TQString & sql )
+{
+ d->lastAt = TQSql::BeforeFirst;
+ TQSqlQuery::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 TQVariant.
+
+ \sa setCalculated()
+*/
+
+TQVariant TQSqlCursor::calculateField( const TQString& )
+{
+ return TQVariant();
+}
+
+/*! \internal
+ Ensure fieldlist is synced with query.
+
+*/
+
+static TQString qTrim( const TQString& s )
+{
+ TQString 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 TQSqlCursor::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 ( TQSqlRecord::isGenerated( i ) ) {
+ TQVariant v = TQSqlQuery::value( j );
+ if ( ( v.type() == TQVariant::String || v.type() == TQVariant::CString ) &&
+ d->infoBuffer[ i ].isTrim() ) {
+ v = qTrim( v.toString() );
+ }
+ TQSqlRecord::setValue( i, v );
+ if ( TQSqlQuery::isNull( j ) )
+ TQSqlRecord::field( i )->setNull();
+ j++;
+ }
+ }
+ if ( haveCalculatedFields ) {
+ for ( i = 0; i < count(); ++i ) {
+ if ( d->infoBuffer[i].isCalculated() )
+ TQSqlRecord::setValue( i, calculateField( fieldName( i ) ) );
+ }
+ }
+ }
+}
+
+/*! \reimp
+
+*/
+
+void TQSqlCursor::afterSeek()
+{
+ sync();
+}
+
+/*!
+ \reimp
+
+ Returns the value of field number \a i.
+*/
+
+TQVariant TQSqlCursor::value( int i ) const
+{
+ return TQSqlRecord::value( i );
+}
+
+/*!
+ \reimp
+
+ Returns the value of the field called \a name.
+*/
+
+TQVariant TQSqlCursor::value( const TQString& name ) const
+{
+ return TQSqlRecord::value( name );
+}
+
+/*! \internal
+ cursors should be filled with TQSqlFieldInfos...
+*/
+void TQSqlCursor::append( const TQSqlField& field )
+{
+ append( TQSqlFieldInfo( field ) );
+}
+/*! \internal
+ cursors should be filled with TQSqlFieldInfos...
+*/
+void TQSqlCursor::insert( int pos, const TQSqlField& field )
+{
+ insert( pos, TQSqlFieldInfo( 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 TQSqlRecord::isNull( \a i )
+*/
+bool TQSqlCursor::isNull( int i ) const
+{
+ return TQSqlRecord::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 TQSqlRecord::isNull( \a name )
+*/
+bool TQSqlCursor::isNull( const TQString& name ) const
+{
+ return TQSqlRecord::isNull( name );
+}
+
+/*! \reimp */
+void TQSqlCursor::setValue( int i, const TQVariant& val )
+{
+#ifdef QT_DEBUG
+ qDebug("TQSqlCursor::setValue(): This will not affect actual database values. Use primeInsert(), primeUpdate() or primeDelete().");
+#endif
+ TQSqlRecord::setValue( i, val );
+}
+
+/*! \reimp */
+void TQSqlCursor::setValue( const TQString& name, const TQVariant& val )
+{
+#ifdef QT_DEBUG
+ qDebug("TQSqlCursor::setValue(): This will not affect actual database values. Use primeInsert(), primeUpdate() or primeDelete().");
+#endif
+ TQSqlRecord::setValue( name, val );
+}
+#endif
diff --git a/src/sql/qsqlcursor.h b/src/sql/qsqlcursor.h
new file mode 100644
index 000000000..8c00f7132
--- /dev/null
+++ b/src/sql/qsqlcursor.h
@@ -0,0 +1,160 @@
+/****************************************************************************
+**
+** Definition of TQSqlCursor class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLCURSOR_H
+#define TQSQLCURSOR_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 TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL
+
+class TQSqlDatabase;
+class TQSqlCursorPrivate;
+
+class TQM_EXPORT_SQL TQSqlCursor : public TQSqlRecord, public TQSqlQuery
+{
+public:
+ TQSqlCursor( const TQString & name = TQString::null, bool autopopulate = TRUE, TQSqlDatabase* db = 0 );
+ TQSqlCursor( const TQSqlCursor & other );
+ TQSqlCursor& operator=( const TQSqlCursor& other );
+ ~TQSqlCursor();
+
+ enum Mode {
+ ReadOnly = 0,
+ Insert = 1,
+ Update = 2,
+ Delete = 4,
+ Writable = 7
+ };
+
+ TQVariant value( int i ) const;
+ TQVariant value( const TQString& name ) const;
+ void setValue( int i, const TQVariant& val );
+ void setValue( const TQString& name, const TQVariant& val );
+ virtual TQSqlIndex primaryIndex( bool prime = TRUE ) const;
+ virtual TQSqlIndex index( const TQStringList& fieldNames ) const;
+ TQSqlIndex index( const TQString& fieldName ) const;
+ TQSqlIndex index( const char* fieldName ) const;
+ virtual void setPrimaryIndex( const TQSqlIndex& idx );
+
+ virtual void append( const TQSqlFieldInfo& fieldInfo );
+ virtual void insert( int pos, const TQSqlFieldInfo& fieldInfo );
+ void remove( int pos );
+ void clear();
+ void setGenerated( const TQString& name, bool generated );
+ void setGenerated( int i, bool generated );
+
+ virtual TQSqlRecord* editBuffer( bool copy = FALSE );
+ virtual TQSqlRecord* primeInsert();
+ virtual TQSqlRecord* primeUpdate();
+ virtual TQSqlRecord* 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 TQString& name, bool calculated );
+ bool isCalculated( const TQString& name ) const;
+ virtual void setTrimmed( const TQString& name, bool trim );
+ bool isTrimmed( const TQString& name ) const;
+
+ bool isReadOnly() const;
+ bool canInsert() const;
+ bool canUpdate() const;
+ bool canDelete() const;
+
+ bool select();
+ bool select( const TQSqlIndex& sort );
+ bool select( const TQSqlIndex & filter, const TQSqlIndex & sort );
+ virtual bool select( const TQString & filter, const TQSqlIndex & sort = TQSqlIndex() );
+
+ virtual void setSort( const TQSqlIndex& sort );
+ TQSqlIndex sort() const;
+ virtual void setFilter( const TQString& filter );
+ TQString filter() const;
+ virtual void setName( const TQString& name, bool autopopulate = TRUE );
+ TQString name() const;
+ TQString toString( const TQString& prefix = TQString::null,
+ const TQString& sep = "," ) const;
+ bool isNull( int i ) const;
+ bool isNull( const TQString& name ) const;
+
+protected:
+ void afterSeek();
+ bool exec( const TQString & sql );
+
+ virtual TQVariant calculateField( const TQString& name );
+ virtual int update( const TQString & filter, bool invalidate = TRUE );
+ virtual int del( const TQString & filter, bool invalidate = TRUE );
+
+ virtual TQString toString( const TQString& prefix, TQSqlField* field, const TQString& fieldSep ) const;
+ virtual TQString toString( TQSqlRecord* rec, const TQString& prefix, const TQString& fieldSep,
+ const TQString& sep ) const;
+ virtual TQString toString( const TQSqlIndex& i, TQSqlRecord* rec, const TQString& prefix,
+ const TQString& fieldSep, const TQString& sep ) const;
+
+private:
+ void sync();
+ int apply( const TQString& q, bool invalidate );
+ int applyPrepared( const TQString& q, bool invalidate );
+ TQSqlRecord& operator=( const TQSqlRecord & list );
+ void append( const TQSqlField& field );
+ void insert( int pos, const TQSqlField& field );
+
+ TQSqlCursorPrivate* d;
+};
+
+
+
+
+#endif // QT_NO_SQL
+#endif
diff --git a/src/sql/qsqldatabase.cpp b/src/sql/qsqldatabase.cpp
new file mode 100644
index 000000000..e54fd124d
--- /dev/null
+++ b/src/sql/qsqldatabase.cpp
@@ -0,0 +1,1332 @@
+/****************************************************************************
+**
+** Implementation of TQSqlDatabase class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlDatabase::defaultConnection = "qt_sql_default_connection";
+
+TQPtrDict<TQSqlDriverExtension> *qt_driver_extension_dict = 0;
+TQPtrDict<TQSqlOpenExtension> *qt_open_extension_dict = 0;
+
+static TQSingleCleanupHandler< TQPtrDict<TQSqlDriverExtension> > qt_driver_ext_cleanup;
+static TQSingleCleanupHandler< TQPtrDict<TQSqlOpenExtension> > qt_open_ext_cleanup;
+
+Q_EXPORT TQPtrDict<TQSqlDriverExtension> *qSqlDriverExtDict()
+{
+ if ( !qt_driver_extension_dict ) {
+ qt_driver_extension_dict = new TQPtrDict<TQSqlDriverExtension>;
+ qt_driver_ext_cleanup.set( &qt_driver_extension_dict );
+ }
+ return qt_driver_extension_dict;
+}
+
+Q_EXPORT TQPtrDict<TQSqlOpenExtension> *qSqlOpenExtDict()
+{
+ if ( !qt_open_extension_dict ) {
+ qt_open_extension_dict = new TQPtrDict<TQSqlOpenExtension>;
+ qt_open_ext_cleanup.set( &qt_open_extension_dict );
+ }
+ return qt_open_extension_dict;
+}
+
+class TQNullResult : public TQSqlResult
+{
+public:
+ TQNullResult(const TQSqlDriver* d): TQSqlResult(d){}
+ ~TQNullResult(){}
+protected:
+ TQVariant data( int ) { return TQVariant(); }
+ bool reset ( const TQString& sqlquery ) { TQString 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; }
+ TQSqlRecord record() {return TQSqlRecord();}
+ int size() {return 0;}
+ int numRowsAffected() {return 0;}
+};
+
+class TQNullDriver : public TQSqlDriver
+{
+public:
+ TQNullDriver(): TQSqlDriver(){}
+ ~TQNullDriver(){}
+ bool hasFeature( DriverFeature /* f */ ) const { return FALSE; } ;
+ bool open( const TQString & ,
+ const TQString & ,
+ const TQString & ,
+ const TQString &,
+ int ) {
+ return FALSE;
+ }
+ void close() {}
+ TQSqlQuery createQuery() const { return TQSqlQuery( new TQNullResult(this) ); }
+};
+
+typedef TQDict<TQSqlDriverCreatorBase> TQDriverDict;
+
+class TQSqlDatabaseManager : public TQObject
+{
+public:
+ TQSqlDatabaseManager( TQObject * parent = 0, const char * name = 0 );
+ ~TQSqlDatabaseManager();
+ static TQSqlDatabase* database( const TQString& name, bool open );
+ static TQSqlDatabase* addDatabase( TQSqlDatabase* db, const TQString & name );
+ static void removeDatabase( const TQString& name );
+ static void removeDatabase( TQSqlDatabase* db );
+ static bool contains( const TQString& name );
+ static TQDriverDict* driverDict();
+
+protected:
+ static TQSqlDatabaseManager* instance();
+ TQDict< TQSqlDatabase > dbDict;
+ TQDriverDict* drDict;
+};
+
+/*!
+ Constructs an SQL database manager.
+*/
+
+TQSqlDatabaseManager::TQSqlDatabaseManager( TQObject * parent, const char * name )
+ : TQObject( 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.
+*/
+
+TQSqlDatabaseManager::~TQSqlDatabaseManager()
+{
+ TQDictIterator< TQSqlDatabase > it( dbDict );
+ while ( it.current() ) {
+ it.current()->close();
+ delete it.current();
+ ++it;
+ }
+ delete drDict;
+}
+
+/*!
+ \internal
+*/
+TQDriverDict* TQSqlDatabaseManager::driverDict()
+{
+ TQSqlDatabaseManager* sqlConnection = instance();
+ if ( !sqlConnection->drDict ) {
+ sqlConnection->drDict = new TQDriverDict();
+ sqlConnection->drDict->setAutoDelete( TRUE );
+ }
+ return sqlConnection->drDict;
+}
+
+
+/*!
+ \internal
+*/
+TQSqlDatabaseManager* TQSqlDatabaseManager::instance()
+{
+ static TQGuardedPtr<TQSqlDatabaseManager> sqlConnection = 0;
+ if ( !sqlConnection ) {
+ if( qApp == 0 ){
+ qFatal( "TQSqlDatabaseManager: A TQApplication object has to be "
+ "instantiated in order to use the SQL module." );
+ return 0;
+ }
+ sqlConnection = new TQSqlDatabaseManager( qApp, "database manager" );
+ }
+ return (TQSqlDatabaseManager*)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.
+*/
+
+TQSqlDatabase* TQSqlDatabaseManager::database( const TQString& name, bool open )
+{
+ if ( !contains( name ) )
+ return 0;
+
+ TQSqlDatabaseManager* sqlConnection = instance();
+ TQSqlDatabase* db = sqlConnection->dbDict.find( name );
+ if ( db && !db->isOpen() && open ) {
+ db->open();
+#ifdef QT_CHECK_RANGE
+ if ( !db->isOpen() )
+ qWarning("TQSqlDatabaseManager::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 TQSqlDatabaseManager::contains( const TQString& name )
+{
+ TQSqlDatabaseManager* sqlConnection = instance();
+ TQSqlDatabase* 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 TQApplication object has been instantiated. Use
+ the output of drivers() to determine whether a particular driver
+ is available or not.
+
+ The returned TQSqlDatabase object is owned by the framework and
+ must not be deleted. If you want to explicitly remove the connection,
+ use removeDatabase().
+
+ \sa TQSqlDatabase database()
+*/
+
+TQSqlDatabase* TQSqlDatabaseManager::addDatabase( TQSqlDatabase* db, const TQString & name )
+{
+ TQSqlDatabaseManager* 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 TQSqlDatabaseManager::removeDatabase( const TQString& name )
+{
+ TQSqlDatabaseManager* 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 TQSqlDatabase 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 TQSqlDatabaseManager::removeDatabase( TQSqlDatabase* db )
+{
+ TQSqlDatabaseManager* sqlConnection = instance();
+ if ( !sqlConnection )
+ return;
+ TQDictIterator< TQSqlDatabase > it( sqlConnection->dbDict );
+ while ( it.current() ) {
+ if ( it.current() == db ) {
+ sqlConnection->dbDict.remove( it.currentKey() );
+ db->close();
+ delete db;
+ break;
+ }
+ ++it;
+ }
+}
+
+class TQSqlDatabasePrivate
+{
+public:
+ TQSqlDatabasePrivate():
+ driver(0),
+#ifndef QT_NO_COMPONENT
+ plugIns(0),
+#endif
+ port(-1) {}
+ ~TQSqlDatabasePrivate()
+ {
+ }
+ TQSqlDriver* driver;
+#ifndef QT_NO_COMPONENT
+ TQPluginManager<TQSqlDriverFactoryInterface> *plugIns;
+#endif
+ TQString dbname;
+ TQString uname;
+ TQString pword;
+ TQString hname;
+ TQString drvName;
+ int port;
+ TQString connOptions;
+};
+
+/*!
+ \class TQSqlDatabase qsqldatabase.h
+ \brief The TQSqlDatabase 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 TQSqlDriver::hasFeature().
+
+ The TQSqlDatabase 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 TQSqlDriver). Result set objects provide the interface
+ for executing and manipulating SQL queries (see TQSqlQuery).
+*/
+
+/*!
+ 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 TQSqlDatabase 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 TQSqlDatabase::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()
+*/
+TQSqlDatabase* TQSqlDatabase::addDatabase( const TQString& type, const TQString& connectionName )
+{
+ return TQSqlDatabaseManager::addDatabase( new TQSqlDatabase( 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 TQSqlDatabase 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 TQt\endlink document for more information about
+ threading and SQL databases.
+*/
+
+TQSqlDatabase* TQSqlDatabase::database( const TQString& connectionName, bool open )
+{
+ return TQSqlDatabaseManager::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 TQSqlDatabase::removeDatabase( const TQString& connectionName )
+{
+ TQSqlDatabaseManager::removeDatabase( connectionName );
+}
+
+/*!
+ \overload
+
+ Removes the database connection \a db from the list of database
+ connections. The TQSqlDatabase 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 TQSqlDatabase::removeDatabase( TQSqlDatabase* db )
+{
+ TQSqlDatabaseManager::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
+ TQStringList list = TQSqlDatabase::drivers();
+ TQStringList::Iterator it = list.begin();
+ while( it != list.end() ) {
+ myProcessing( *it );
+ ++it;
+ }
+ \endcode
+*/
+
+TQStringList TQSqlDatabase::drivers()
+{
+ TQStringList l;
+
+#ifndef QT_NO_COMPONENT
+ TQPluginManager<TQSqlDriverFactoryInterface> *plugIns;
+ plugIns = new TQPluginManager<TQSqlDriverFactoryInterface>( IID_QSqlDriverFactory, TQApplication::libraryPaths(), "/sqldrivers" );
+
+ l = plugIns->featureList();
+ delete plugIns;
+#endif
+
+ TQDictIterator<TQSqlDriverCreatorBase> itd( *TQSqlDatabaseManager::driverDict() );
+ while ( itd.current() ) {
+ if ( !l.contains( itd.currentKey() ) )
+ l << itd.currentKey();
+ ++itd;
+ }
+
+#ifdef QT_SQL_POSTGRES
+ if ( !l.contains( "TQPSQL7" ) )
+ l << "TQPSQL7";
+#endif
+#ifdef QT_SQL_MYSQL
+ if ( !l.contains( "TQMYSQL3" ) )
+ l << "TQMYSQL3";
+#endif
+#ifdef QT_SQL_ODBC
+ if ( !l.contains( "TQODBC3" ) )
+ l << "TQODBC3";
+#endif
+#ifdef QT_SQL_OCI
+ if ( !l.contains( "TQOCI8" ) )
+ l << "TQOCI8";
+#endif
+#ifdef QT_SQL_TDS
+ if ( !l.contains( "TQTDS7" ) )
+ l << "TQTDS7";
+#endif
+#ifdef QT_SQL_DB2
+ if ( !l.contains( "TQDB2" ) )
+ l << "TQDB2";
+#endif
+#ifdef QT_SQL_SQLITE
+ if ( !l.contains( "TQSQLITE" ) )
+ l << "TQSQLITE";
+#endif
+#ifdef QT_SQL_IBASE
+ if ( !l.contains( "TQIBASE" ) )
+ l << "TQIBASE";
+#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
+ TQSqlDatabase::registerSqlDriver( "MYDRIVER", new TQSqlDriverCreator<MyDatabaseDriver> );
+ TQSqlDatabase* db = TQSqlDatabase::addDatabase( "MYDRIVER" );
+ ...
+ \endcode
+
+ \warning The framework takes ownership of the \a creator pointer,
+ so it should not be deleted.
+*/
+void TQSqlDatabase::registerSqlDriver( const TQString& name, const TQSqlDriverCreatorBase* creator )
+{
+ TQSqlDatabaseManager::driverDict()->remove( name );
+ if ( creator )
+ TQSqlDatabaseManager::driverDict()->insert( name, creator );
+}
+
+/*!
+ Returns TRUE if the list of database connections contains \a
+ connectionName; otherwise returns FALSE.
+*/
+
+bool TQSqlDatabase::contains( const TQString& connectionName )
+{
+ return TQSqlDatabaseManager::contains( connectionName );
+}
+
+
+/*!
+ Creates a TQSqlDatabase 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 TQODBC3 \i ODBC Driver (includes Microsoft SQL Server)
+ \row \i TQOCI8 \i Oracle Call Interface Driver
+ \row \i TQPSQL7 \i PostgreSQL v6.x and v7.x Driver
+ \row \i TQTDS7 \i Sybase Adaptive Server
+ \row \i TQMYSQL3 \i MySQL Driver
+ \row \i TQDB2 \i IBM DB2, v7.1 and higher
+ \row \i TQSQLITE \i SQLite Driver
+ \row \i TQIBASE \i Borland Interbase Driver
+ \endtable
+
+ Additional third party drivers, including your own custom drivers,
+ can be loaded dynamically.
+
+ \sa registerSqlDriver()
+*/
+
+TQSqlDatabase::TQSqlDatabase( const TQString& type, const TQString& name, TQObject * parent, const char * objname )
+ : TQObject( 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.
+*/
+
+TQSqlDatabase::TQSqlDatabase( TQSqlDriver* driver, TQObject * parent, const char * objname )
+ : TQObject( parent, objname )
+{
+ d = new TQSqlDatabasePrivate();
+ d->driver = driver;
+}
+
+/*!
+ \internal
+
+ Create the actual driver instance \a type.
+*/
+
+void TQSqlDatabase::init( const TQString& type, const TQString& )
+{
+ d = new TQSqlDatabasePrivate();
+ d->drvName = type;
+
+ if ( !d->driver ) {
+
+#ifdef QT_SQL_POSTGRES
+ if ( type == "TQPSQL7" )
+ d->driver = new TQPSQLDriver();
+#endif
+
+#ifdef QT_SQL_MYSQL
+ if ( type == "TQMYSQL3" )
+ d->driver = new TQMYSQLDriver();
+#endif
+
+#ifdef QT_SQL_ODBC
+ if ( type == "TQODBC3" )
+ d->driver = new TQODBCDriver();
+#endif
+
+#ifdef QT_SQL_OCI
+ if ( type == "TQOCI8" )
+ d->driver = new TQOCIDriver();
+#endif
+
+#ifdef QT_SQL_TDS
+ if ( type == "TQTDS7" )
+ d->driver = new TQTDSDriver();
+#endif
+
+#ifdef QT_SQL_DB2
+ if ( type == "TQDB2" )
+ d->driver = new TQDB2Driver();
+#endif
+
+#ifdef QT_SQL_SQLITE
+ if ( type == "TQSQLITE" )
+ d->driver = new TQSQLiteDriver();
+#endif
+
+#ifdef QT_SQL_IBASE
+ if ( type == "TQIBASE" )
+ d->driver = new TQIBaseDriver();
+#endif
+
+ }
+
+ if ( !d->driver ) {
+ TQDictIterator<TQSqlDriverCreatorBase> it( *TQSqlDatabaseManager::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 TQPluginManager<TQSqlDriverFactoryInterface>( IID_QSqlDriverFactory, TQApplication::libraryPaths(), "/sqldrivers" );
+
+ TQInterfacePtr<TQSqlDriverFactoryInterface> iface = 0;
+ d->plugIns->queryInterface( type, &iface );
+ if( iface )
+ d->driver = iface->create( type );
+ }
+#endif
+
+ if ( !d->driver ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQSqlDatabase: %s driver not loaded", type.latin1() );
+ qWarning( "TQSqlDatabase: available drivers: %s", drivers().join(" ").latin1() );
+#endif
+ d->driver = new TQNullDriver();
+ d->driver->setLastError( TQSqlError( "Driver not loaded", "Driver not loaded" ) );
+ }
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQSqlDatabase::~TQSqlDatabase()
+{
+ 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 TQSqlQuery object.
+ Use lastError() to retrieve error information. If \a query is
+ TQString::null, an empty, invalid query is returned and lastError()
+ is not affected.
+
+ \sa TQSqlQuery lastError()
+*/
+
+TQSqlQuery TQSqlDatabase::exec( const TQString & query ) const
+{
+ TQSqlQuery 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 TQSqlDatabase::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 TQSqlDatabase::open( const TQString& user, const TQString& password )
+{
+ setUserName( user );
+ return d->driver->open( d->dbname, user, password, d->hname,
+ d->port, d->connOptions );
+}
+
+/*!
+ Closes the database connection, freeing any resources actquired.
+
+ \sa removeDatabase()
+*/
+
+void TQSqlDatabase::close()
+{
+ d->driver->close();
+}
+
+/*!
+ Returns TRUE if the database connection is currently open;
+ otherwise returns FALSE.
+*/
+
+bool TQSqlDatabase::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 TQSqlDatabase::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 TQSqlDriver::hasFeature() commit() rollback()
+*/
+
+bool TQSqlDatabase::transaction()
+{
+ if ( !d->driver->hasFeature( TQSqlDriver::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 TQSqlDriver::hasFeature() rollback()
+*/
+
+bool TQSqlDatabase::commit()
+{
+ if ( !d->driver->hasFeature( TQSqlDriver::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 TQSqlDriver::hasFeature() commit() transaction()
+*/
+
+bool TQSqlDatabase::rollback()
+{
+ if ( !d->driver->hasFeature( TQSqlDriver::Transactions ) )
+ return FALSE;
+ return d->driver->rollbackTransaction();
+}
+
+/*!
+ \property TQSqlDatabase::databaseName
+ \brief the name of the database
+
+ Note that the database name is the TNS Service Name for the TQOCI8
+ (Oracle) driver.
+
+ For the TQODBC3 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 = TQSqlDatabase::addDatabase( "TQODBC3" );
+ db->setDatabaseName( "DRIVER={Microsoft Access Driver (*.mdb)};FIL={MS Access};DBQ=myaccessfile.mdb" );
+ if ( db->open() ) {
+ // success!
+ }
+ ...
+ \endcode
+ ("FIL" is the retquired spelling in Microsoft's API.)
+
+ There is no default value.
+*/
+
+void TQSqlDatabase::setDatabaseName( const TQString& name )
+{
+ d->dbname = name;
+}
+
+/*!
+ \property TQSqlDatabase::userName
+ \brief the user name connected to the database
+
+ There is no default value.
+*/
+
+void TQSqlDatabase::setUserName( const TQString& name )
+{
+ d->uname = name;
+}
+
+/*!
+ \property TQSqlDatabase::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
+ TQt. Use the open() call that takes a password as parameter to
+ avoid this behaviour.
+
+ \sa open()
+*/
+
+void TQSqlDatabase::setPassword( const TQString& password )
+{
+ d->pword = password;
+}
+
+/*!
+ \property TQSqlDatabase::hostName
+ \brief the host name where the database resides
+
+ There is no default value.
+*/
+
+void TQSqlDatabase::setHostName( const TQString& host )
+{
+ d->hname = host;
+}
+
+/*!
+ \property TQSqlDatabase::port
+ \brief the port used to connect to the database
+
+ There is no default value.
+*/
+
+void TQSqlDatabase::setPort( int p )
+{
+ d->port = p;
+}
+
+TQString TQSqlDatabase::databaseName() const
+{
+ return d->dbname;
+}
+
+TQString TQSqlDatabase::userName() const
+{
+ return d->uname;
+}
+
+TQString TQSqlDatabase::password() const
+{
+ return d->pword;
+}
+
+TQString TQSqlDatabase::hostName() const
+{
+ return d->hname;
+}
+
+/*!
+ Returns the name of the driver used by the database connection.
+*/
+TQString TQSqlDatabase::driverName() const
+{
+ return d->drvName;
+}
+
+int TQSqlDatabase::port() const
+{
+ return d->port;
+}
+
+/*!
+ Returns the database driver used to access the database
+ connection.
+*/
+
+TQSqlDriver* TQSqlDatabase::driver() const
+{
+ return d->driver;
+}
+
+/*!
+ Returns information about the last error that occurred on the
+ database. See TQSqlError for more information.
+*/
+
+TQSqlError TQSqlDatabase::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
+ TQStringList list = myDatabase.tables();
+ TQStringList::Iterator it = list.begin();
+ while( it != list.end() ) {
+ myProcessing( *it );
+ ++it;
+ }
+ \endcode
+*/
+
+TQStringList TQSqlDatabase::tables() const
+{
+ return tables( TQSql::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
+ TQStringList list = myDatabase.tables( TQSql::Tables | TQSql::Views );
+ TQStringList::Iterator it = list.begin();
+ while( it != list.end() ) {
+ myProcessing( *it );
+ ++it;
+ }
+ \endcode
+*/
+
+TQStringList TQSqlDatabase::tables( TQSql::TableType type ) const
+{
+ return d->driver->tables( TQString::number( (int)type ) );
+}
+
+/*!
+ Returns the primary index for table \a tablename. If no primary
+ index exists an empty TQSqlIndex will be returned.
+*/
+
+TQSqlIndex TQSqlDatabase::primaryIndex( const TQString& tablename ) const
+{
+ return d->driver->primaryIndex( tablename );
+}
+
+
+/*!
+ Returns a TQSqlRecord 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()
+*/
+
+TQSqlRecord TQSqlDatabase::record( const TQString& tablename ) const
+{
+ return d->driver->record( tablename );
+}
+
+
+/*!
+ \overload
+
+ Returns a TQSqlRecord 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()
+*/
+
+TQSqlRecord TQSqlDatabase::record( const TQSqlQuery& query ) const
+{
+ return d->driver->record( query );
+}
+
+/*!
+ Returns a TQSqlRecordInfo populated with meta data about the table
+ or view \a tablename. If no such table (or view) exists, an empty
+ record is returned.
+
+ \sa TQSqlRecordInfo, TQSqlFieldInfo, record()
+*/
+TQSqlRecordInfo TQSqlDatabase::recordInfo( const TQString& tablename ) const
+{
+ return d->driver->recordInfo( tablename );
+}
+
+/*!
+ \overload
+
+ Returns a TQSqlRecordInfo object with meta data for the TQSqlQuery
+ \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 TQSqlRecordInfo, TQSqlFieldInfo, record()
+*/
+TQSqlRecordInfo TQSqlDatabase::recordInfo( const TQSqlQuery& query ) const
+{
+ return d->driver->recordInfo( query );
+}
+
+/*!
+ \property TQSqlDatabase::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 retquiressl
+ \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( "retquiressl=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 TQSqlDatabase::setConnectOptions( const TQString& options )
+{
+ d->connOptions = options;
+}
+
+TQString TQSqlDatabase::connectOptions() const
+{
+ return d->connOptions;
+}
+
+/*!
+ Returns TRUE if a driver called \a name is available; otherwise
+ returns FALSE.
+
+ \sa drivers()
+*/
+
+bool TQSqlDatabase::isDriverAvailable( const TQString& name )
+{
+ TQStringList l = drivers();
+ TQStringList::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 TQPSQL7 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 TQt is installed.)
+ This will pull in the code that is needed to use the PostgreSQL
+ client library and to instantiate a TQPSQLDriver 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" );
+ TQPSQLDriver* drv = new TQPSQLDriver( con );
+ TQSqlDatabase* db = TQSqlDatabase::addDatabase( drv ); // becomes the new default connection
+ TQSqlQuery q;
+ q.exec( "SELECT * FROM people" );
+ ...
+ \endcode
+
+ The above code sets up a PostgreSQL connection and instantiates a
+ TQPSQLDriver object. Next, addDatabase() is called to add the
+ connection to the known connections so that it can be used by the
+ TQt SQL classes. When a driver is instantiated with a connection
+ handle (or set of handles), TQt 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 TQPSQL7
+ \i TQPSQLDriver
+ \i PGconn* connection
+ \i \c qsql_psql.cpp
+ \row
+ \i TQMYSQL3
+ \i TQMYSQLDriver
+ \i MYSQL* connection
+ \i \c qsql_mysql.cpp
+ \row
+ \i TQOCI8
+ \i TQOCIDriver
+ \i OCIEnv* environment, OCIError* error, OCISvcCtx* serviceContext
+ \i \c qsql_oci.cpp
+ \row
+ \i TQODBC3
+ \i TQODBCDriver
+ \i SQLHANDLE environment, SQLHANDLE connection
+ \i \c qsql_odbc.cpp
+ \row
+ \i TQDB2
+ \i TQDB2
+ \i SQLHANDLE environment, SQLHANDLE connection
+ \i \c qsql_db2.cpp
+ \row
+ \i TQTDS7
+ \i TQTDSDriver
+ \i LOGINREC* loginRecord, DBPROCESS* dbProcess, const TQString& hostName
+ \i \c qsql_tds.cpp
+ \row
+ \i TQSQLITE
+ \i TQSQLiteDriver
+ \i sqlite* connection
+ \i \c qsql_sqlite.cpp
+ \row
+ \i TQIBASE
+ \i TQIBaseDriver
+ \i isc_db_handle connection
+ \i \c qsql_ibase.cpp
+ \endtable
+
+ Note: The host name (or service name) is needed when constructing
+ the TQTDSDriver for creating new connections for internal
+ queries. This is to prevent the simultaneous usage of several
+ TQSqlQuery/\l{TQSqlCursor} objects from blocking each other.
+
+ \warning The SQL framework takes ownership of the \a driver pointer,
+ and it should not be deleted. The returned TQSqlDatabase object is
+ owned by the framework and must not be deleted. If you want to
+ explicitly remove the connection, use removeDatabase()
+
+ \sa drivers()
+*/
+
+TQSqlDatabase* TQSqlDatabase::addDatabase( TQSqlDriver* driver, const TQString& connectionName )
+{
+ return TQSqlDatabaseManager::addDatabase( new TQSqlDatabase( driver ), connectionName );
+}
+#endif // QT_NO_SQL
diff --git a/src/sql/qsqldatabase.h b/src/sql/qsqldatabase.h
new file mode 100644
index 000000000..bd679278c
--- /dev/null
+++ b/src/sql/qsqldatabase.h
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Definition of TQSqlDatabase class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLDATABASE_H
+#define TQSQLDATABASE_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 TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL
+
+class TQSqlError;
+class TQSqlDriver;
+class TQSqlIndex;
+class TQSqlRecord;
+class TQSqlRecordInfo;
+class TQSqlDatabasePrivate;
+
+class TQM_EXPORT_SQL TQSqlDriverCreatorBase
+{
+public:
+ virtual TQSqlDriver* createObject() = 0;
+};
+
+template <class type>
+class TQM_EXPORT_SQL TQSqlDriverCreator: public TQSqlDriverCreatorBase
+{
+public:
+ TQSqlDriver* createObject() { return new type; }
+};
+
+class TQM_EXPORT_SQL TQSqlDatabase : public TQObject
+{
+ Q_OBJECT
+ Q_PROPERTY( TQString databaseName READ databaseName WRITE setDatabaseName )
+ Q_PROPERTY( TQString userName READ userName WRITE setUserName )
+ Q_PROPERTY( TQString password READ password WRITE setPassword )
+ Q_PROPERTY( TQString hostName READ hostName WRITE setHostName )
+ Q_PROPERTY( int port READ port WRITE setPort )
+ Q_PROPERTY( TQString connectOptions READ connectOptions WRITE setConnectOptions )
+
+public:
+ ~TQSqlDatabase();
+
+ bool open();
+ bool open( const TQString& user, const TQString& password );
+ void close();
+ bool isOpen() const;
+ bool isOpenError() const;
+ TQStringList tables() const;
+ TQStringList tables( TQSql::TableType type ) const;
+ TQSqlIndex primaryIndex( const TQString& tablename ) const;
+ TQSqlRecord record( const TQString& tablename ) const;
+ TQSqlRecord record( const TQSqlQuery& query ) const;
+ TQSqlRecordInfo recordInfo( const TQString& tablename ) const;
+ TQSqlRecordInfo recordInfo( const TQSqlQuery& query ) const;
+ TQSqlQuery exec( const TQString& query = TQString::null ) const;
+ TQSqlError lastError() const;
+
+ bool transaction();
+ bool commit();
+ bool rollback();
+
+ virtual void setDatabaseName( const TQString& name );
+ virtual void setUserName( const TQString& name );
+ virtual void setPassword( const TQString& password );
+ virtual void setHostName( const TQString& host );
+ virtual void setPort( int p );
+ void setConnectOptions( const TQString& options = TQString::null );
+ TQString databaseName() const;
+ TQString userName() const;
+ TQString password() const;
+ TQString hostName() const;
+ TQString driverName() const;
+ int port() const;
+ TQString connectOptions() const;
+
+ TQSqlDriver* driver() const;
+
+ // MOC_SKIP_BEGIN
+ QT_STATIC_CONST char * const defaultConnection;
+ // MOC_SKIP_END
+
+ static TQSqlDatabase* addDatabase( const TQString& type, const TQString& connectionName = defaultConnection );
+ static TQSqlDatabase* addDatabase( TQSqlDriver* driver, const TQString& connectionName = defaultConnection );
+ static TQSqlDatabase* database( const TQString& connectionName = defaultConnection, bool open = TRUE );
+ static void removeDatabase( const TQString& connectionName );
+ static void removeDatabase( TQSqlDatabase* db );
+ static bool contains( const TQString& connectionName = defaultConnection );
+ static TQStringList drivers();
+ static void registerSqlDriver( const TQString& name, const TQSqlDriverCreatorBase* creator ); // ### 4.0: creator should not be const
+ static bool isDriverAvailable( const TQString& name );
+
+protected:
+ TQSqlDatabase( const TQString& type, const TQString& name, TQObject * parent=0, const char * objname=0 );
+ TQSqlDatabase( TQSqlDriver* driver, TQObject * parent=0, const char * objname=0 );
+private:
+ void init( const TQString& type, const TQString& name );
+ TQSqlDatabasePrivate* d;
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ TQSqlDatabase( const TQSqlDatabase & );
+ TQSqlDatabase &operator=( const TQSqlDatabase & );
+#endif
+
+};
+
+#endif // QT_NO_SQL
+#endif
diff --git a/src/sql/qsqldriver.cpp b/src/sql/qsqldriver.cpp
new file mode 100644
index 000000000..522011e80
--- /dev/null
+++ b/src/sql/qsqldriver.cpp
@@ -0,0 +1,509 @@
+/****************************************************************************
+**
+** Implementation of TQSqlDriver class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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!
+TQPtrDict<TQSqlDriverExtension> *qSqlDriverExtDict();
+TQPtrDict<TQSqlOpenExtension> *qSqlOpenExtDict();
+
+/*!
+ \class TQSqlDriver qsqldriver.h
+ \brief The TQSqlDriver class is an abstract base class for accessing
+ SQL databases.
+
+ \ingroup database
+ \module sql
+
+ This class should not be used directly. Use TQSqlDatabase instead.
+*/
+
+/*!
+ Default constructor. Creates a new driver with parent \a parent,
+ called \a name.
+
+*/
+
+TQSqlDriver::TQSqlDriver( TQObject * parent, const char * name )
+: TQObject(parent, name),
+ dbState(0),
+ error()
+{
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQSqlDriver::~TQSqlDriver()
+{
+}
+
+/*!
+ \fn bool TQSqlDriver::open( const TQString& db, const TQString& user,
+ const TQString& password, const TQString& 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 TQSqlDriver::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 TQSqlQuery TQSqlDriver::createQuery() const
+
+ Creates an empty SQL result on the database. Derived classes must
+ reimplement this function and return a TQSqlQuery object
+ appropriate for their database to the caller.
+
+*/
+
+//void TQSqlDriver::destroyResult( TQSqlResult* r ) const
+//{
+// if ( r )
+// delete r;
+//}
+
+/*!
+ Returns TRUE if the database connection is open; otherwise returns
+ FALSE.
+*/
+
+bool TQSqlDriver::isOpen() const
+{
+ if ( !qSqlDriverExtDict()->isEmpty() ) {
+ TQSqlDriverExtension *ext = qSqlDriverExtDict()->find( (TQSqlDriver *) 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 TQSqlDriver::isOpenError() const
+{
+ return ((dbState & DBState_OpenError) == DBState_OpenError);
+}
+
+/*!
+ \enum TQSqlDriver::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
+ TQSqlQuery::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 TQt SQL driver\endlink documentation.
+
+ \sa hasFeature()
+*/
+
+/*!
+ \fn bool TQSqlDriver::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 TQSqlDriver::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 TQSqlDriver::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 TQSqlDriver::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 TQSqlDriver::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 TQSqlDriver::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 TQSqlDriver::setLastError( const TQSqlError& e )
+{
+ error = e;
+}
+
+/*!
+ Returns a TQSqlError object which contains information about the
+ last error that occurred on the database.
+*/
+
+TQSqlError TQSqlDriver::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 TQSql::TableTypes as text.
+ An empty string should be treated as TQSql::Tables for
+ downward compatibility.
+
+ \sa TQSql::TableType
+*/
+
+TQStringList TQSqlDriver::tables( const TQString& ) const
+{
+ return TQStringList();
+}
+
+/*!
+ Returns the primary index for table \a tableName. Returns an empty
+ TQSqlIndex if the table doesn't have a primary index. The default
+ implementation returns an empty index.
+*/
+
+TQSqlIndex TQSqlDriver::primaryIndex( const TQString& ) const
+{
+ return TQSqlIndex();
+}
+
+
+/*!
+ Returns a TQSqlRecord 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.
+*/
+
+TQSqlRecord TQSqlDriver::record( const TQString& ) const
+{
+ return TQSqlRecord();
+}
+
+/*!
+ \overload
+
+ Returns a TQSqlRecord populated with the names of the fields in the
+ SQL \a query. The default implementation returns an empty record.
+*/
+
+TQSqlRecord TQSqlDriver::record( const TQSqlQuery& ) const
+{
+ return TQSqlRecord();
+}
+
+/*!
+ Returns a TQSqlRecordInfo object with meta data about the table \a
+ tablename.
+*/
+TQSqlRecordInfo TQSqlDriver::recordInfo( const TQString& tablename ) const
+{
+ return TQSqlRecordInfo( record( tablename ) );
+}
+
+/*!
+ \overload
+
+ Returns a TQSqlRecordInfo object with meta data for the TQSqlQuery
+ \a query. Note that this overloaded function may return less
+ information than the recordInfo() function which takes the name of
+ a table as parameter.
+*/
+TQSqlRecordInfo TQSqlDriver::recordInfo( const TQSqlQuery& query ) const
+{
+ return TQSqlRecordInfo( 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".
+*/
+
+TQString TQSqlDriver::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 TQVariant::toString().
+
+*/
+TQString TQSqlDriver::formatValue( const TQSqlField* field, bool trimStrings ) const
+{
+ TQString r;
+ if ( field->isNull() )
+ r = nullText();
+ else {
+ switch ( field->type() ) {
+ case TQVariant::Int:
+ case TQVariant::UInt:
+ if ( field->value().type() == TQVariant::Bool )
+ r = field->value().toBool() ? "1" : "0";
+ else
+ r = field->value().toString();
+ break;
+ case TQVariant::Date:
+ if ( field->value().toDate().isValid() )
+ r = "'" + field->value().toDate().toString( TQt::ISODate ) + "'";
+ else
+ r = nullText();
+ break;
+ case TQVariant::Time:
+ if ( field->value().toTime().isValid() )
+ r = "'" + field->value().toTime().toString( TQt::ISODate ) + "'";
+ else
+ r = nullText();
+ break;
+ case TQVariant::DateTime:
+ if ( field->value().toDateTime().isValid() )
+ r = "'" +
+ field->value().toDateTime().toString( TQt::ISODate ) + "'";
+ else
+ r = nullText();
+ break;
+ case TQVariant::String:
+ case TQVariant::CString: {
+ TQString 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( TQChar( '\'' ), "''" );
+ r = "'" + result + "'";
+ break;
+ }
+ case TQVariant::Bool:
+ if ( field->value().toBool() )
+ r = "1";
+ else
+ r = "0";
+ break;
+ case TQVariant::ByteArray : {
+ if ( hasFeature( BLOB ) ) {
+ TQByteArray ba = field->value().toByteArray();
+ TQString 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 TQSqlDriver::open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts )
+{
+ if ( !qSqlOpenExtDict()->isEmpty() ) {
+ TQSqlOpenExtension *ext = qSqlOpenExtDict()->find( (TQSqlDriver *) 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/src/sql/qsqldriver.h b/src/sql/qsqldriver.h
new file mode 100644
index 000000000..68ed94fc4
--- /dev/null
+++ b/src/sql/qsqldriver.h
@@ -0,0 +1,125 @@
+/****************************************************************************
+**
+** Definition of TQSqlDriver class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLDRIVER_H
+#define TQSQLDRIVER_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 TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL
+
+class TQSqlDriverExtension;
+
+class TQSqlDatabase;
+
+class TQM_EXPORT_SQL TQSqlDriver : public TQObject
+{
+ friend class TQSqlDatabase;
+ Q_OBJECT
+public:
+ enum DriverFeature { Transactions, QuerySize, BLOB, Unicode, PreparedQueries,
+ NamedPlaceholders, PositionalPlaceholders };
+
+ TQSqlDriver( TQObject * parent=0, const char * name=0 );
+ ~TQSqlDriver();
+ bool isOpen() const;
+ bool isOpenError() const;
+
+ virtual bool beginTransaction();
+ virtual bool commitTransaction();
+ virtual bool rollbackTransaction();
+ virtual TQStringList tables( const TQString& tableType ) const;
+ virtual TQSqlIndex primaryIndex( const TQString& tableName ) const;
+ virtual TQSqlRecord record( const TQString& tableName ) const;
+ virtual TQSqlRecord record( const TQSqlQuery& query ) const;
+ virtual TQSqlRecordInfo recordInfo( const TQString& tablename ) const;
+ virtual TQSqlRecordInfo recordInfo( const TQSqlQuery& query ) const;
+ virtual TQString nullText() const;
+ virtual TQString formatValue( const TQSqlField* field, bool trimStrings = FALSE ) const;
+ TQSqlError lastError() const;
+
+ virtual bool hasFeature( DriverFeature f ) const = 0;
+ virtual bool open( const TQString & db,
+ const TQString & user = TQString::null,
+ const TQString & password = TQString::null,
+ const TQString & host = TQString::null,
+ int port = -1 ) = 0;
+ virtual void close() = 0;
+ virtual TQSqlQuery createQuery() const = 0;
+
+ // ### remove for 4.0
+ bool open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts );
+protected:
+ virtual void setOpen( bool o );
+ virtual void setOpenError( bool e );
+ virtual void setLastError( const TQSqlError& e );
+private:
+ // ### This class needs a d-pointer in 4.0.
+ int dbState;
+ TQSqlError error;
+#if defined(Q_DISABLE_COPY)
+ TQSqlDriver( const TQSqlDriver & );
+ TQSqlDriver &operator=( const TQSqlDriver & );
+#endif
+};
+
+#endif // QT_NO_SQL
+#endif
diff --git a/src/sql/qsqldriverinterface_p.h b/src/sql/qsqldriverinterface_p.h
new file mode 100644
index 000000000..dd2f539bb
--- /dev/null
+++ b/src/sql/qsqldriverinterface_p.h
@@ -0,0 +1,85 @@
+/****************************************************************************
+**
+** Definition of TQSqlDriverInterface class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLDRIVERINTERFACE_H
+#define TQSQLDRIVERINTERFACE_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the TQt 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 TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL
+
+#ifndef QT_NO_COMPONENT
+
+// {EDDD5AD5-DF3C-400c-A711-163B72FE5F61}
+#ifndef IID_QSqlDriverFactory
+#define IID_QSqlDriverFactory TQUuid(0xeddd5ad5, 0xdf3c, 0x400c, 0xa7, 0x11, 0x16, 0x3b, 0x72, 0xfe, 0x5f, 0x61)
+#endif
+
+class TQSqlDriver;
+
+struct TQM_EXPORT_SQL TQSqlDriverFactoryInterface : public TQFeatureListInterface
+{
+ virtual TQSqlDriver* create( const TQString& name ) = 0;
+};
+
+#endif //QT_NO_COMPONENT
+#endif // QT_NO_SQL
+
+#endif // TQSQLDRIVERINTERFACE_P_H
diff --git a/src/sql/qsqldriverplugin.cpp b/src/sql/qsqldriverplugin.cpp
new file mode 100644
index 000000000..ff3620e5c
--- /dev/null
+++ b/src/sql/qsqldriverplugin.cpp
@@ -0,0 +1,161 @@
+/****************************************************************************
+**
+** Implementation of TQSqlDriverPlugin class
+**
+** Created : 2001-09-20
+**
+** Copyright (C) 2001-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlDriverPlugin qsqldriverplugin.h
+ \brief The TQSqlDriverPlugin class provides an abstract base for custom TQSqlDriver 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 TQt.
+
+ 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 TQt 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 TQStringList TQSqlDriverPlugin::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 TQSqlDriver* TQSqlDriverPlugin::create( const TQString& key )
+
+ Creates and returns a TQSqlDriver object for the driver key \a key.
+ The driver key is usually the class name of the retquired driver.
+
+ \sa keys()
+*/
+
+class TQSqlDriverPluginPrivate : public TQSqlDriverFactoryInterface
+{
+public:
+ TQSqlDriverPluginPrivate( TQSqlDriverPlugin *p )
+ : plugin( p )
+ {
+ }
+ virtual ~TQSqlDriverPluginPrivate();
+
+ TQRESULT queryInterface( const TQUuid &iid, TQUnknownInterface **iface );
+ Q_REFCOUNT;
+
+ TQStringList featureList() const;
+ TQSqlDriver *create( const TQString &key );
+
+private:
+ TQSqlDriverPlugin *plugin;
+};
+
+TQSqlDriverPluginPrivate::~TQSqlDriverPluginPrivate()
+{
+ delete plugin;
+}
+
+TQRESULT TQSqlDriverPluginPrivate::queryInterface( const TQUuid &iid, TQUnknownInterface **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 TQE_NOINTERFACE;
+
+ (*iface)->addRef();
+ return TQS_OK;
+}
+
+TQStringList TQSqlDriverPluginPrivate::featureList() const
+{
+ return plugin->keys();
+}
+
+TQSqlDriver *TQSqlDriverPluginPrivate::create( const TQString &key )
+{
+ return plugin->create( key );
+}
+
+/*!
+ Constructs a SQL driver plugin. This is invoked automatically by
+ the \c Q_EXPORT_PLUGIN macro.
+*/
+
+TQSqlDriverPlugin::TQSqlDriverPlugin()
+ : TQGPlugin( d = new TQSqlDriverPluginPrivate( this ) )
+{
+}
+
+/*!
+ Destroys the SQL driver plugin.
+
+ You never have to call this explicitly. TQt destroys a plugin
+ automatically when it is no longer used.
+*/
+TQSqlDriverPlugin::~TQSqlDriverPlugin()
+{
+ // don't delete d, as this is deleted by d
+}
+
+#endif // QT_NO_COMPONENT
+#endif // QT_NO_SQL
diff --git a/src/sql/qsqldriverplugin.h b/src/sql/qsqldriverplugin.h
new file mode 100644
index 000000000..591c384b1
--- /dev/null
+++ b/src/sql/qsqldriverplugin.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+**
+** Definition of TQSqlDriverPlugin class
+**
+** Created : 2001-09-20
+**
+** Copyright (C) 2001-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLDRIVERPLUGIN_H
+#define TQSQLDRIVERPLUGIN_H
+
+#ifndef QT_H
+#include "qgplugin.h"
+#include "qstringlist.h"
+#endif // QT_H
+
+#ifndef QT_NO_SQL
+#ifndef QT_NO_COMPONENT
+
+class TQSqlDriver;
+class TQSqlDriverPluginPrivate;
+
+class Q_EXPORT TQSqlDriverPlugin : public TQGPlugin
+{
+ Q_OBJECT
+public:
+ TQSqlDriverPlugin();
+ ~TQSqlDriverPlugin();
+
+ virtual TQStringList keys() const = 0;
+ virtual TQSqlDriver *create( const TQString &key ) = 0;
+
+private:
+ TQSqlDriverPluginPrivate *d;
+};
+
+#endif // QT_NO_COMPONENT
+#endif // QT_NO_SQL
+
+#endif // TQSQLDRIVERPLUGIN_H
diff --git a/src/sql/qsqleditorfactory.cpp b/src/sql/qsqleditorfactory.cpp
new file mode 100644
index 000000000..72afcd188
--- /dev/null
+++ b/src/sql/qsqleditorfactory.cpp
@@ -0,0 +1,221 @@
+/****************************************************************************
+**
+** Implementation of TQSqlEditorFactory class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlEditorFactory qsqleditorfactory.h
+ \brief The TQSqlEditorFactory class is used to create the editors
+ used by TQDataTable and TQSqlForm.
+
+ \ingroup database
+ \module sql
+
+ TQSqlEditorFactory is used by TQDataTable and TQSqlForm to
+ automatically create appropriate editors for a given TQSqlField.
+ For example if the field is a TQVariant::String a TQLineEdit would
+ be the default editor, whereas a TQVariant::Int's default editor
+ would be a TQSpinBox.
+
+ If you want to create different editors for fields with the same
+ data type, subclass TQSqlEditorFactory and reimplement the
+ createEditor() function.
+
+ \sa TQDataTable, TQSqlForm
+*/
+
+
+/*!
+ Constructs a SQL editor factory with parent \a parent, called \a
+ name.
+*/
+
+TQSqlEditorFactory::TQSqlEditorFactory ( TQObject * parent, const char * name )
+ : TQEditorFactory( parent, name )
+{
+
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQSqlEditorFactory::~TQSqlEditorFactory()
+{
+
+}
+
+static TQSqlEditorFactory * defaultfactory = 0;
+static TQCleanupHandler< TQSqlEditorFactory > qsql_cleanup_editor_factory;
+
+/*!
+ Returns an instance of a default editor factory.
+*/
+
+TQSqlEditorFactory * TQSqlEditorFactory::defaultFactory()
+{
+ if( defaultfactory == 0 ){
+ defaultfactory = new TQSqlEditorFactory();
+ qsql_cleanup_editor_factory.add( &defaultfactory );
+ }
+
+ return defaultfactory;
+}
+
+/*!
+ Replaces the default editor factory with \a factory. All
+ TQDataTable and TQSqlForm instantiations will use this new factory
+ for creating field editors. \e{TQSqlEditorFactory takes ownership
+ of \a factory, and destroys it when it is no longer needed.}
+*/
+
+void TQSqlEditorFactory::installDefaultFactory( TQSqlEditorFactory * 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 TQVariant
+ \a variant.
+
+ The widget that is returned has the parent \a parent (which may be
+ zero). If \a variant is invalid, 0 is returned.
+*/
+
+TQWidget * TQSqlEditorFactory::createEditor( TQWidget * parent,
+ const TQVariant & variant )
+{
+ return TQEditorFactory::createEditor( parent, variant );
+}
+
+/*!
+ \overload
+
+ Creates and returns the appropriate editor for the TQSqlField \a
+ field.
+*/
+
+TQWidget * TQSqlEditorFactory::createEditor( TQWidget * parent,
+ const TQSqlField * field )
+{
+ if ( !field ) {
+ return 0;
+ }
+
+ TQWidget * w = 0;
+ switch( field->type() ){
+ case TQVariant::Invalid:
+ w = 0;
+ break;
+ case TQVariant::Bool:
+ w = new TQComboBox( parent, "qt_editor_bool" );
+ ((TQComboBox *) w)->insertItem( "False" );
+ ((TQComboBox *) w)->insertItem( "True" );
+ break;
+ case TQVariant::UInt:
+ w = new TQSpinBox( 0, 2147483647, 1, parent, "qt_editor_spinbox" );
+ break;
+ case TQVariant::Int:
+ w = new TQSpinBox( -2147483647, 2147483647, 1, parent, "qt_editor_int" );
+ break;
+ case TQVariant::LongLong:
+ case TQVariant::ULongLong:
+ case TQVariant::String:
+ case TQVariant::CString:
+ case TQVariant::Double:
+ w = new TQLineEdit( parent, "qt_editor_double" );
+ ((TQLineEdit*)w)->setFrame( FALSE );
+ break;
+ case TQVariant::Date:
+ w = new TQDateEdit( parent, "qt_editor_date" );
+ break;
+ case TQVariant::Time:
+ w = new TQTimeEdit( parent, "qt_editor_time" );
+ break;
+ case TQVariant::DateTime:
+ w = new TQDateTimeEdit( parent, "qt_editor_datetime" );
+ break;
+#ifndef QT_NO_LABEL
+ case TQVariant::Pixmap:
+ w = new TQLabel( parent, "qt_editor_pixmap" );
+ break;
+#endif
+ case TQVariant::Palette:
+ case TQVariant::ColorGroup:
+ case TQVariant::Color:
+ case TQVariant::Font:
+ case TQVariant::Brush:
+ case TQVariant::Bitmap:
+ case TQVariant::Cursor:
+ case TQVariant::Map:
+ case TQVariant::StringList:
+ case TQVariant::Rect:
+ case TQVariant::Size:
+ case TQVariant::IconSet:
+ case TQVariant::Point:
+ case TQVariant::PointArray:
+ case TQVariant::Region:
+ case TQVariant::SizePolicy:
+ case TQVariant::ByteArray:
+ default:
+ w = new TQWidget( parent, "qt_editor_default" );
+ break;
+ }
+ return w;
+}
+
+#endif // QT_NO_SQL
diff --git a/src/sql/qsqleditorfactory.h b/src/sql/qsqleditorfactory.h
new file mode 100644
index 000000000..f8d2c1339
--- /dev/null
+++ b/src/sql/qsqleditorfactory.h
@@ -0,0 +1,77 @@
+/****************************************************************************
+**
+** Definition of TQSqlEditorFactory class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLEDITORFACTORY_H
+#define TQSQLEDITORFACTORY_H
+
+#ifndef QT_H
+#include "qeditorfactory.h"
+#endif // QT_H
+
+#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL )
+#define TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL_EDIT_WIDGETS
+
+class TQSqlField;
+
+class TQM_EXPORT_SQL TQSqlEditorFactory : public TQEditorFactory
+{
+public:
+ TQSqlEditorFactory ( TQObject * parent = 0, const char * name = 0 );
+ ~TQSqlEditorFactory();
+ virtual TQWidget * createEditor( TQWidget * parent, const TQVariant & variant );
+ virtual TQWidget * createEditor( TQWidget * parent, const TQSqlField * field );
+
+ static TQSqlEditorFactory * defaultFactory();
+ static void installDefaultFactory( TQSqlEditorFactory * factory );
+
+private:
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ TQSqlEditorFactory( const TQSqlEditorFactory & );
+ TQSqlEditorFactory &operator=( const TQSqlEditorFactory & );
+#endif
+};
+
+#endif // QT_NO_SQL
+#endif // TQSQLEDITORFACTORY_H
diff --git a/src/sql/qsqlerror.cpp b/src/sql/qsqlerror.cpp
new file mode 100644
index 000000000..9dce821f9
--- /dev/null
+++ b/src/sql/qsqlerror.cpp
@@ -0,0 +1,228 @@
+/****************************************************************************
+**
+** Implementation of TQSqlError class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlError qsqlerror.h
+ \brief The TQSqlError 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 TQSqlError::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.
+*/
+
+TQSqlError::TQSqlError( const TQString& driverText,
+ const TQString& databaseText,
+ int type,
+ int number )
+: driverError(driverText),
+ databaseError(databaseText),
+ errorType(type),
+ errorNumber(number)
+{
+}
+
+/*!
+ Creates a copy of \a other.
+*/
+
+TQSqlError::TQSqlError( const TQSqlError& other )
+: driverError(other.driverError),
+ databaseError(other.databaseError),
+ errorType(other.errorType),
+ errorNumber(other.errorNumber)
+{
+}
+
+/*!
+ Sets the error equal to \a other.
+*/
+
+TQSqlError& TQSqlError::operator=( const TQSqlError& other )
+{
+ driverError = other.driverError;
+ databaseError = other.databaseError;
+ errorType = other.errorType;
+ errorNumber = other.errorNumber;
+ return *this;
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQSqlError::~TQSqlError()
+{
+}
+
+/*!
+ Returns the text of the error as reported by the driver. This may
+ contain database-specific descriptions.
+*/
+TQString TQSqlError::driverText() const
+{
+ return driverError;
+}
+
+/*!
+ Sets the driver error text to the value of \a driverText.
+*/
+
+void TQSqlError::setDriverText( const TQString& driverText )
+{
+ driverError = driverText;
+}
+
+/*!
+ Returns the text of the error as reported by the database. This
+ may contain database-specific descriptions.
+*/
+
+TQString TQSqlError::databaseText() const
+{
+ return databaseError;
+}
+
+/*!
+ Sets the database error text to the value of \a databaseText.
+*/
+
+void TQSqlError::setDatabaseText( const TQString& databaseText )
+{
+ databaseError = databaseText;
+}
+
+/*!
+ Returns the error type, or -1 if the type cannot be determined.
+
+ \sa TQSqlError::Type.
+*/
+
+int TQSqlError::type() const
+{
+ return errorType;
+}
+
+/*!
+ Sets the error type to the value of \a type.
+*/
+
+void TQSqlError::setType( int type )
+{
+ errorType = type;
+}
+
+/*!
+ Returns the database-specific error number, or -1 if it cannot be
+ determined.
+*/
+
+int TQSqlError::number() const
+{
+ return errorNumber;
+}
+
+/*!
+ Sets the database-specific error number to \a number.
+*/
+
+void TQSqlError::setNumber( int number )
+{
+ errorNumber = number;
+}
+
+/*!
+ This is a convenience function that returns databaseText() and
+ driverText() concatenated into a single string.
+
+ \sa showMessage(), driverText(), databaseText()
+*/
+
+TQString TQSqlError::text() const
+{
+ if ( databaseError.endsWith("\n") )
+ return databaseError + driverError;
+ else
+ return databaseError + " " + driverError;
+}
+
+/*!
+ \obsolete
+
+ This is a convenience function that pops up a TQMessageBox
+ 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 TQSqlError::showMessage( const TQString& msg ) const
+{
+#ifndef QT_NO_MESSAGEBOX
+ TQMessageBox::warning( NULL, "SQL Error", msg + text(),
+ TQMessageBox::Ok, TQMessageBox::NoButton );
+#endif // QT_NO_MESSAGEBOX
+}
+#endif // QT_NO_SQL
diff --git a/src/sql/qsqlerror.h b/src/sql/qsqlerror.h
new file mode 100644
index 000000000..abe6f2fe7
--- /dev/null
+++ b/src/sql/qsqlerror.h
@@ -0,0 +1,93 @@
+/****************************************************************************
+**
+** Definition of TQSqlError class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLERROR_H
+#define TQSQLERROR_H
+
+#ifndef QT_H
+#include "qstring.h"
+#endif // QT_H
+
+#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL )
+#define TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL
+
+class TQM_EXPORT_SQL TQSqlError
+{
+public:
+ enum Type {
+ None,
+ Connection,
+ Statement,
+ Transaction,
+ Unknown
+ };
+ TQSqlError( const TQString& driverText = TQString::null,
+ const TQString& databaseText = TQString::null,
+ int type = TQSqlError::None,
+ int number = -1 );
+ TQSqlError( const TQSqlError& other );
+ TQSqlError& operator=( const TQSqlError& other );
+ virtual ~TQSqlError();
+
+ TQString driverText() const;
+ virtual void setDriverText( const TQString& driverText );
+ TQString databaseText() const;
+ virtual void setDatabaseText( const TQString& databaseText );
+ int type() const;
+ virtual void setType( int type );
+ int number() const;
+ virtual void setNumber( int number );
+ TQString text() const;
+ void showMessage( const TQString& msg = TQString::null ) const;
+
+private:
+ TQString driverError;
+ TQString databaseError;
+ int errorType;
+ int errorNumber;
+};
+
+#endif // QT_NO_SQL
+#endif
diff --git a/src/sql/qsqlextension_p.cpp b/src/sql/qsqlextension_p.cpp
new file mode 100644
index 000000000..21a6d2104
--- /dev/null
+++ b/src/sql/qsqlextension_p.cpp
@@ -0,0 +1,169 @@
+/****************************************************************************
+**
+** Implementation of the TQSqlExtension class
+**
+** Created : 2002-06-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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
+TQSqlExtension::TQSqlExtension()
+ : bindm( BindByPosition ), bindCount( 0 )
+{
+}
+
+TQSqlExtension::~TQSqlExtension()
+{
+}
+
+bool TQSqlExtension::prepare( const TQString& /*query*/ )
+{
+ return FALSE;
+}
+
+bool TQSqlExtension::exec()
+{
+ return FALSE;
+}
+
+void TQSqlExtension::bindValue( const TQString& placeholder, const TQVariant& val, TQSql::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 TQSqlExtension::bindValue( int pos, const TQVariant& val, TQSql::ParameterType tp )
+{
+ bindm = BindByPosition;
+ index[ pos ] = TQString::number( pos );
+ TQString nm = TQString::number( pos );
+ values[ nm ] = Param( val, tp );
+}
+
+void TQSqlExtension::addBindValue( const TQVariant& val, TQSql::ParameterType tp )
+{
+ bindm = BindByPosition;
+ bindValue( bindCount++, val, tp );
+}
+
+void TQSqlExtension::clearValues()
+{
+ values.clear();
+ bindCount = 0;
+}
+
+void TQSqlExtension::resetBindCount()
+{
+ bindCount = 0;
+}
+
+void TQSqlExtension::clearIndex()
+{
+ index.clear();
+ holders.clear();
+}
+
+void TQSqlExtension::clear()
+{
+ clearValues();
+ clearIndex();
+}
+
+TQVariant TQSqlExtension::parameterValue( const TQString& holder )
+{
+ return values[ holder ].value;
+}
+
+TQVariant TQSqlExtension::parameterValue( int pos )
+{
+ return values[ index[ pos ] ].value;
+}
+
+TQVariant TQSqlExtension::boundValue( const TQString& holder ) const
+{
+ return values[ holder ].value;
+}
+
+TQVariant TQSqlExtension::boundValue( int pos ) const
+{
+ return values[ index[ pos ] ].value;
+}
+
+TQMap<TQString, TQVariant> TQSqlExtension::boundValues() const
+{
+ TQMap<TQString, Param>::ConstIterator it;
+ TQMap<TQString, TQVariant> m;
+ if ( bindm == BindByName ) {
+ for ( it = values.begin(); it != values.end(); ++it )
+ m.insert( it.key(), it.data().value );
+ } else {
+ TQString key, tmp, fmt;
+ fmt.sprintf( "%%0%dd", TQString::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;
+}
+
+TQSqlExtension::BindMethod TQSqlExtension::bindMethod()
+{
+ return bindm;
+}
+
+TQSqlDriverExtension::TQSqlDriverExtension()
+{
+}
+
+TQSqlDriverExtension::~TQSqlDriverExtension()
+{
+}
+
+TQSqlOpenExtension::TQSqlOpenExtension()
+{
+}
+
+TQSqlOpenExtension::~TQSqlOpenExtension()
+{
+}
+#endif
diff --git a/src/sql/qsqlextension_p.h b/src/sql/qsqlextension_p.h
new file mode 100644
index 000000000..e8b1a2c53
--- /dev/null
+++ b/src/sql/qsqlextension_p.h
@@ -0,0 +1,148 @@
+/****************************************************************************
+**
+** Definition of the TQSqlExtension class
+**
+** Created : 2002-06-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLEXTENSION_P_H
+#define TQSQLEXTENSION_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the TQt API. It exists for the convenience
+// of other TQt 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 TQM_EXPORT_SQL
+#define TQM_TEMPLATE_EXTERN_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#define TQM_TEMPLATE_EXTERN_SQL Q_TEMPLATE_EXTERN
+#endif
+
+struct Param {
+ Param( const TQVariant& v = TQVariant(), TQSql::ParameterType t = TQSql::In ): value( v ), typ( t ) {}
+ TQVariant value;
+ TQSql::ParameterType typ;
+ Q_DUMMY_COMPARISON_OPERATOR(Param)
+};
+
+struct Holder {
+ Holder( const TQString& hldr = TQString::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; }
+ TQString holderName;
+ int holderPos;
+};
+
+#define Q_DEFINED_QSQLEXTENSION
+#include "qwinexport.h"
+
+class TQM_EXPORT_SQL TQSqlExtension {
+public:
+ TQSqlExtension();
+ virtual ~TQSqlExtension();
+ virtual bool prepare( const TQString& query );
+ virtual bool exec();
+ virtual void bindValue( const TQString& holder, const TQVariant& value, TQSql::ParameterType = TQSql::In );
+ virtual void bindValue( int pos, const TQVariant& value, TQSql::ParameterType = TQSql::In );
+ virtual void addBindValue( const TQVariant& value, TQSql::ParameterType = TQSql::In );
+ virtual TQVariant parameterValue( const TQString& holder );
+ virtual TQVariant parameterValue( int pos );
+ TQVariant boundValue( const TQString& holder ) const;
+ TQVariant boundValue( int pos ) const;
+ TQMap<TQString, TQVariant> 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;
+
+ TQMap<int, TQString> index;
+ typedef TQMap<TQString, Param> ValueMap;
+ ValueMap values;
+
+ // convenience container for TQSqlQuery
+ // to map holders <-> positions
+ typedef TQValueVector<Holder> HolderVector;
+ HolderVector holders;
+};
+
+class TQM_EXPORT_SQL TQSqlDriverExtension
+{
+public:
+ TQSqlDriverExtension();
+ virtual ~TQSqlDriverExtension();
+ virtual bool isOpen() const = 0;
+};
+
+class TQM_EXPORT_SQL TQSqlOpenExtension
+{
+public:
+ TQSqlOpenExtension();
+ virtual ~TQSqlOpenExtension();
+ virtual bool open( const TQString& db,
+ const TQString& user,
+ const TQString& password,
+ const TQString& host,
+ int port,
+ const TQString& connOpts ) = 0;
+};
+#endif
+
+#endif
diff --git a/src/sql/qsqlfield.cpp b/src/sql/qsqlfield.cpp
new file mode 100644
index 000000000..b197b797e
--- /dev/null
+++ b/src/sql/qsqlfield.cpp
@@ -0,0 +1,563 @@
+/****************************************************************************
+**
+** Implementation of TQSqlField class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlField qsqlfield.h
+ \brief The TQSqlField class manipulates the fields in SQL database tables
+ and views.
+
+ \ingroup database
+ \module sql
+
+ TQSqlField 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 TQVariants. Using an incompatible
+ type is not permitted. For example:
+
+ \code
+ TQSqlField f( "myfield", TQVariant::Int );
+ f.setValue( TQPixmap() ); // will not work
+ \endcode
+
+ However, the field will attempt to cast certain data types to the
+ field data type where possible:
+
+ \code
+ TQSqlField f( "myfield", TQVariant::Int );
+ f.setValue( TQString("123") ); // casts TQString to int
+ \endcode
+
+ TQSqlField objects are rarely created explicitly in application
+ code. They are usually accessed indirectly through \l TQSqlRecord
+ or \l TQSqlCursor which already contain a list of fields. For
+ example:
+
+ \code
+ TQSqlCursor cur( "Employee" ); // create cursor using the 'Employee' table
+ TQSqlField* 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
+ TQSqlCursor cur( "Employee" );
+ cur.setValue( "name", "Dave" );
+ ...
+ \endcode
+*/
+
+/*!
+ Constructs an empty field called \a fieldName of type \a type.
+*/
+
+TQSqlField::TQSqlField( const TQString& fieldName, TQVariant::Type type )
+ : nm(fieldName), ro(FALSE), nul(FALSE)
+{
+ d = new TQSqlFieldPrivate();
+ d->type = type;
+ val.cast( type );
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+
+TQSqlField::TQSqlField( const TQSqlField& other )
+ : nm( other.nm ), val( other.val ), ro( other.ro ), nul( other.nul )
+{
+ d = new TQSqlFieldPrivate();
+ d->type = other.d->type;
+}
+
+/*!
+ Sets the field equal to \a other.
+*/
+
+TQSqlField& TQSqlField::operator=( const TQSqlField& 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 TQSqlField::operator==(const TQSqlField& 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.
+*/
+
+TQSqlField::~TQSqlField()
+{
+ delete d;
+}
+
+
+/*!
+ \fn TQVariant TQSqlField::value() const
+
+ Returns the value of the field as a TQVariant.
+*/
+
+/*!
+ 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 TQString to an
+ integer data type. For example:
+
+ \code
+ TQSqlCursor cur( "Employee" ); // 'Employee' table
+ TQSqlField* f = cur.field( "student_count" ); // an integer field
+ ...
+ f->setValue( myLineEdit->text() ); // cast the line edit text to an integer
+ \endcode
+
+ \sa isReadOnly()
+*/
+
+void TQSqlField::setValue( const TQVariant& value )
+{
+ if ( isReadOnly() )
+ return;
+ if ( value.type() != d->type ) {
+ if ( !val.canCast( d->type ) )
+ qWarning("TQSqlField::setValue: %s cannot cast from %s to %s",
+ nm.local8Bit().data(), value.typeName(), TQVariant::typeToName( d->type ) );
+ }
+ val = value;
+
+ if ( value.isNull() )
+ nul = TRUE;
+ else
+ nul = val.type() == TQVariant::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 TQSqlField::clear( bool nullify )
+{
+ if ( isReadOnly() )
+ return;
+ TQVariant v;
+ v.cast( type() );
+ val = v;
+ if ( nullify )
+ nul = TRUE;
+}
+
+/*!
+ \fn void TQSqlField::setName( const TQString& name )
+
+ Sets the name of the field to \a name.
+*/
+
+void TQSqlField::setName( const TQString& name )
+{
+ nm = name;
+}
+
+/*!
+ \fn void TQSqlField::setNull()
+
+ Sets the field to NULL and clears the value using clear(). If the
+ field is read-only, nothing happens.
+
+ \sa isReadOnly() clear()
+*/
+
+void TQSqlField::setNull()
+{
+ clear( TRUE );
+}
+
+/*!
+ \fn void TQSqlField::setReadOnly( bool readOnly )
+
+ Sets the read only flag of the field's value to \a readOnly.
+
+ \sa setValue()
+*/
+void TQSqlField::setReadOnly( bool readOnly )
+{
+ ro = readOnly;
+}
+
+/*!
+ \fn TQString TQSqlField::name() const
+
+ Returns the name of the field.
+*/
+
+/*!
+ \fn TQVariant::Type TQSqlField::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 TQSqlField::isReadOnly() const
+
+ Returns TRUE if the field's value is read only; otherwise returns
+ FALSE.
+*/
+
+/*!
+ \fn bool TQSqlField::isNull() const
+
+ Returns TRUE if the field is currently NULL; otherwise returns
+ FALSE.
+*/
+
+
+/******************************************/
+/******* TQSqlFieldInfo Impl ******/
+/******************************************/
+
+struct TQSqlFieldInfoPrivate
+{
+ int retquired, len, prec, typeID;
+ uint generated: 1;
+ uint trim: 1;
+ uint calculated: 1;
+ TQString name;
+ TQString typeName;
+ TQVariant::Type typ;
+ TQVariant defValue;
+};
+
+/*!
+ \class TQSqlFieldInfo qsqlfield.h
+ \brief The TQSqlFieldInfo class stores meta data associated with a SQL field.
+
+ \ingroup database
+ \module sql
+
+ TQSqlFieldInfo objects only store meta data; field values are
+ stored in TQSqlField objects.
+
+ All values must be set in the constructor, and may be retrieved
+ using isRetquired(), type(), length(), precision(), defaultValue(),
+ name(), isGenerated() and typeID().
+*/
+
+/*!
+ Constructs a TQSqlFieldInfo 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 TQVariant.
+ \row \i \a retquired \i greater than 0 if the field is retquired, 0
+ if its value can be NULL and less than 0 if it cannot be
+ determined whether the field is retquired 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. TQVariant() 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 TQSqlCursor.
+ \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 TQSqlCursor and overriding
+ TQSqlCursor::calculateField().
+ \endtable
+*/
+TQSqlFieldInfo::TQSqlFieldInfo( const TQString& name,
+ TQVariant::Type typ,
+ int retquired,
+ int len,
+ int prec,
+ const TQVariant& defValue,
+ int typeID,
+ bool generated,
+ bool trim,
+ bool calculated )
+{
+ d = new TQSqlFieldInfoPrivate();
+ d->name = name;
+ d->typ = typ;
+ d->retquired = retquired;
+ 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.
+*/
+TQSqlFieldInfo::TQSqlFieldInfo( const TQSqlFieldInfo & other )
+{
+ d = new TQSqlFieldInfoPrivate( *(other.d) );
+}
+
+/*!
+ Creates a TQSqlFieldInfo object with the type and the name of the
+ TQSqlField \a other. If \a generated is TRUE this field will be
+ included in auto-generated SQL statments, e.g. in TQSqlCursor.
+*/
+TQSqlFieldInfo::TQSqlFieldInfo( const TQSqlField & other, bool generated )
+{
+ d = new TQSqlFieldInfoPrivate();
+ d->name = other.name();
+ d->typ = other.type();
+ d->retquired = -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.
+*/
+TQSqlFieldInfo::~TQSqlFieldInfo()
+{
+ delete d;
+}
+
+/*!
+ Assigns \a other to this field info and returns a reference to it.
+*/
+TQSqlFieldInfo& TQSqlFieldInfo::operator=( const TQSqlFieldInfo& other )
+{
+ delete d;
+ d = new TQSqlFieldInfoPrivate( *(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 TQSqlFieldInfo::operator==( const TQSqlFieldInfo& f ) const
+{
+ return ( d->name == f.d->name &&
+ d->typ == f.d->typ &&
+ d->retquired == f.d->retquired &&
+ 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 TQSqlField based on the information in this
+ TQSqlFieldInfo.
+*/
+TQSqlField TQSqlFieldInfo::toField() const
+{ return TQSqlField( d->name, d->typ ); }
+
+/*!
+ Returns a value greater than 0 if the field is retquired (NULL
+ values are not allowed), 0 if it isn't retquired (NULL values are
+ allowed) or less than 0 if it cannot be determined whether the
+ field is retquired or not.
+*/
+int TQSqlFieldInfo::isRetquired() const
+{ return d->retquired; }
+
+/*!
+ Returns the field's type or TQVariant::Invalid if the type is
+ unknown.
+*/
+TQVariant::Type TQSqlFieldInfo::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 TQSqlFieldInfo::length() const
+{ return d->len; }
+
+/*!
+ Returns the field's precision or -1 if the field has no precision
+ or it cannot be determined.
+*/
+int TQSqlFieldInfo::precision() const
+{ return d->prec; }
+
+/*!
+ Returns the field's default value or an empty TQVariant 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.
+*/
+TQVariant TQSqlFieldInfo::defaultValue() const
+{ return d->defValue; }
+
+/*!
+ Returns the name of the field in the SQL table.
+*/
+TQString TQSqlFieldInfo::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 TQSqlFieldInfo::typeID() const
+{ return d->typeID; }
+
+/*!
+ Returns TRUE if the field should be included in auto-generated
+ SQL statments, e.g. in TQSqlCursor; otherwise returns FALSE.
+
+ \sa setGenerated()
+*/
+bool TQSqlFieldInfo::isGenerated() const
+{ return d->generated; }
+
+/*!
+ Returns TRUE if trailing whitespace should be removed from
+ character fields; otherwise returns FALSE.
+
+ \sa setTrim()
+*/
+bool TQSqlFieldInfo::isTrim() const
+{ return d->trim; }
+
+/*!
+ Returns TRUE if the field is calculated; otherwise returns FALSE.
+
+ \sa setCalculated()
+*/
+bool TQSqlFieldInfo::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 TQSqlFieldInfo::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 TQSqlCursor).
+
+ \sa isGenerated()
+*/
+void TQSqlFieldInfo::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
+ TQSqlCursor and overriding TQSqlCursor::calculateField().
+
+ \sa isCalculated()
+*/
+void TQSqlFieldInfo::setCalculated( bool calc )
+{ d->calculated = calc; }
+
+#endif
diff --git a/src/sql/qsqlfield.h b/src/sql/qsqlfield.h
new file mode 100644
index 000000000..4811fbad9
--- /dev/null
+++ b/src/sql/qsqlfield.h
@@ -0,0 +1,154 @@
+/****************************************************************************
+**
+** Definition of TQSqlField class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLFIELD_H
+#define TQSQLFIELD_H
+
+#ifndef QT_H
+#include "qstring.h"
+#include "qvariant.h"
+#endif // QT_H
+
+#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL )
+#define TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL
+
+class TQSqlFieldPrivate
+{
+public:
+ TQVariant::Type type;
+};
+
+class TQM_EXPORT_SQL TQSqlField
+{
+public:
+ TQSqlField( const TQString& fieldName = TQString::null, TQVariant::Type type = TQVariant::Invalid );
+ TQSqlField( const TQSqlField& other );
+ TQSqlField& operator=( const TQSqlField& other );
+ bool operator==(const TQSqlField& other) const;
+ virtual ~TQSqlField();
+
+ virtual void setValue( const TQVariant& value );
+ virtual TQVariant value() const;
+ virtual void setName( const TQString& name );
+ TQString name() const;
+ virtual void setNull();
+ bool isNull() const;
+ virtual void setReadOnly( bool readOnly );
+ bool isReadOnly() const;
+ void clear( bool nullify = TRUE );
+ TQVariant::Type type() const;
+
+private:
+ TQString nm;
+ TQVariant val;
+ uint ro: 1;
+ uint nul: 1;
+ TQSqlFieldPrivate* d;
+};
+
+inline TQVariant TQSqlField::value() const
+{ return val; }
+
+inline TQString TQSqlField::name() const
+{ return nm; }
+
+inline bool TQSqlField::isNull() const
+{ return nul; }
+
+inline bool TQSqlField::isReadOnly() const
+{ return ro; }
+
+inline TQVariant::Type TQSqlField::type() const
+{ return d->type; }
+
+
+/******************************************/
+/******* TQSqlFieldInfo Class ******/
+/******************************************/
+
+struct TQSqlFieldInfoPrivate;
+
+class TQM_EXPORT_SQL TQSqlFieldInfo
+{
+public:
+ TQSqlFieldInfo( const TQString& name = TQString::null,
+ TQVariant::Type typ = TQVariant::Invalid,
+ int retquired = -1,
+ int len = -1,
+ int prec = -1,
+ const TQVariant& defValue = TQVariant(),
+ int sqlType = 0,
+ bool generated = TRUE,
+ bool trim = FALSE,
+ bool calculated = FALSE );
+ TQSqlFieldInfo( const TQSqlFieldInfo & other );
+ TQSqlFieldInfo( const TQSqlField & other, bool generated = TRUE );
+ virtual ~TQSqlFieldInfo();
+ TQSqlFieldInfo& operator=( const TQSqlFieldInfo& other );
+ bool operator==( const TQSqlFieldInfo& f ) const;
+
+ TQSqlField toField() const;
+ int isRetquired() const;
+ TQVariant::Type type() const;
+ int length() const;
+ int precision() const;
+ TQVariant defaultValue() const;
+ TQString 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:
+ TQSqlFieldInfoPrivate* d;
+};
+
+
+#endif // QT_NO_SQL
+#endif
diff --git a/src/sql/qsqlform.cpp b/src/sql/qsqlform.cpp
new file mode 100644
index 000000000..726597442
--- /dev/null
+++ b/src/sql/qsqlform.cpp
@@ -0,0 +1,403 @@
+/****************************************************************************
+**
+** Implementation of TQSqlForm class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlFormPrivate
+{
+public:
+ TQSqlFormPrivate() : propertyMap( 0 ), buf( 0 ), dirty( FALSE ) {}
+ ~TQSqlFormPrivate() { if ( propertyMap ) delete propertyMap; }
+ TQStringList fld;
+ TQDict<TQWidget> wgt;
+ TQMap< TQWidget *, TQSqlField * > map;
+ TQSqlPropertyMap * propertyMap;
+ TQSqlRecord* buf;
+ bool dirty;
+};
+
+/*!
+ \class TQSqlForm
+ \brief The TQSqlForm class creates and manages data entry forms
+ tied to SQL databases.
+
+ \ingroup database
+ \mainclass
+ \module sql
+
+ Typical use of a TQSqlForm 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 TQSqlForm.
+ \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 TQSqlForm does not access the database directly, but
+ most often via TQSqlFields which are part of a TQSqlCursor. A
+ TQSqlCursor::insert(), TQSqlCursor::update() or TQSqlCursor::del()
+ call is needed to actually write values to the database.
+
+ Some sample code to initialize a form successfully:
+
+ \code
+ TQLineEdit myEditor( this );
+ TQSqlForm myForm( this );
+ TQSqlCursor 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 TQSqlPropertyMap. The form
+ uses this object to get or set the value of a widget.
+
+ Note that \link designer-manual.book TQt Designer\endlink provides
+ a visual means of creating data-aware forms.
+
+ \sa installPropertyMap(), TQSqlPropertyMap
+*/
+
+
+/*!
+ Constructs a TQSqlForm with parent \a parent and called \a name.
+*/
+TQSqlForm::TQSqlForm( TQObject * parent, const char * name )
+ : TQObject( parent, name )
+{
+ d = new TQSqlFormPrivate();
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+TQSqlForm::~TQSqlForm()
+{
+ delete d;
+}
+
+/*!
+ Installs a custom TQSqlPropertyMap. This is useful if you plan to
+ create your own custom editor widgets.
+
+ TQSqlForm takes ownership of \a pmap, so \a pmap is deleted when
+ TQSqlForm goes out of scope.
+
+ \sa TQDataTable::installEditorFactory()
+*/
+void TQSqlForm::installPropertyMap( TQSqlPropertyMap * 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 TQSqlForm::setRecord( TQSqlRecord* 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 TQSqlForm::insert( TQWidget * widget, const TQString& field )
+{
+ d->dirty = TRUE;
+ d->wgt.insert( field, widget );
+ d->fld += field;
+}
+
+/*!
+ \overload
+
+ Removes \a field from the form.
+*/
+
+void TQSqlForm::remove( const TQString& 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 TQSqlForm::insert( TQWidget * widget, TQSqlField * field )
+{
+ d->map[widget] = field;
+}
+
+/*!
+ Removes a \a widget, and hence the field it's mapped to, from the
+ form.
+*/
+
+void TQSqlForm::remove( TQWidget * 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 TQSqlForm::clearValues( bool nullify )
+{
+ TQMap< TQWidget *, TQSqlField * >::Iterator it;
+ for( it = d->map.begin(); it != d->map.end(); ++it ){
+ TQSqlField* f = (*it);
+ if ( f )
+ f->clear( nullify );
+ }
+ readFields();
+}
+
+/*!
+ Removes every widget, and the fields they're mapped to, from the form.
+*/
+void TQSqlForm::clear()
+{
+ d->dirty = TRUE;
+ d->fld.clear();
+ clearMap();
+}
+
+/*!
+ Returns the number of widgets in the form.
+*/
+uint TQSqlForm::count() const
+{
+ return (uint)d->map.count();
+}
+
+/*!
+ Returns the \a{i}-th widget in the form. Useful for traversing
+ the widgets in the form.
+*/
+TQWidget * TQSqlForm::widget( uint i ) const
+{
+ TQMap< TQWidget *, TQSqlField * >::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.
+*/
+TQWidget * TQSqlForm::fieldToWidget( TQSqlField * field ) const
+{
+ TQMap< TQWidget *, TQSqlField * >::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.
+*/
+TQSqlField * TQSqlForm::widgetToField( TQWidget * 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 TQSqlForm::readFields()
+{
+ sync();
+ TQSqlField * f;
+ TQMap< TQWidget *, TQSqlField * >::Iterator it;
+ TQSqlPropertyMap * pmap = (d->propertyMap == 0) ?
+ TQSqlPropertyMap::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 TQSqlCursor::insert(), TQSqlCursor::update()
+ or TQSqlCursor::del() as appropriate.
+*/
+void TQSqlForm::writeFields()
+{
+ sync();
+ TQSqlField * f;
+ TQMap< TQWidget *, TQSqlField * >::Iterator it;
+ TQSqlPropertyMap * pmap = (d->propertyMap == 0) ?
+ TQSqlPropertyMap::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 TQSqlForm::readField( TQWidget * widget )
+{
+ sync();
+ TQSqlField * field = 0;
+ TQSqlPropertyMap * pmap = (d->propertyMap == 0) ?
+ TQSqlPropertyMap::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 TQSqlForm::writeField( TQWidget * widget )
+{
+ sync();
+ TQSqlField * field = 0;
+ TQSqlPropertyMap * pmap = (d->propertyMap == 0) ?
+ TQSqlPropertyMap::defaultMap() : d->propertyMap;
+ field = widgetToField( widget );
+ if( field )
+ field->setValue( pmap->property( widget ) );
+}
+
+/*! \internal
+*/
+
+void TQSqlForm::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 TQSqlForm::clearMap()
+{
+ d->map.clear();
+}
+
+#endif // QT_NO_SQL
diff --git a/src/sql/qsqlform.h b/src/sql/qsqlform.h
new file mode 100644
index 000000000..8b13816fe
--- /dev/null
+++ b/src/sql/qsqlform.h
@@ -0,0 +1,108 @@
+/****************************************************************************
+**
+** Definition of TQSqlForm class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLFORM_H
+#define TQSQLFORM_H
+
+#ifndef QT_H
+#include "qobject.h"
+#include "qmap.h"
+#endif // QT_H
+
+#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL )
+#define TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL_FORM
+
+class TQSqlField;
+class TQSqlRecord;
+class TQSqlEditorFactory;
+class TQSqlPropertyMap;
+class TQWidget;
+class TQSqlFormPrivate;
+
+class TQM_EXPORT_SQL TQSqlForm : public TQObject
+{
+ Q_OBJECT
+public:
+ TQSqlForm( TQObject * parent = 0, const char * name = 0 );
+ ~TQSqlForm();
+
+ virtual void insert( TQWidget * widget, const TQString& field );
+ virtual void remove( const TQString& field );
+ uint count() const;
+
+ TQWidget * widget( uint i ) const;
+ TQSqlField * widgetToField( TQWidget * widget ) const;
+ TQWidget * fieldToWidget( TQSqlField * field ) const;
+
+ void installPropertyMap( TQSqlPropertyMap * map );
+
+ virtual void setRecord( TQSqlRecord* buf );
+
+public slots:
+ virtual void readField( TQWidget * widget );
+ virtual void writeField( TQWidget * widget );
+ virtual void readFields();
+ virtual void writeFields();
+
+ virtual void clear();
+ virtual void clearValues( bool nullify = FALSE );
+
+protected:
+ virtual void insert( TQWidget * widget, TQSqlField * field );
+ virtual void remove( TQWidget * widget );
+ void clearMap();
+
+private:
+ virtual void sync();
+ TQSqlFormPrivate* d;
+
+#if defined(Q_DISABLE_COPY) // Disabled copy constructor and operator=
+ TQSqlForm( const TQSqlForm & );
+ TQSqlForm &operator=( const TQSqlForm & );
+#endif
+};
+
+#endif // QT_NO_SQL
+#endif // TQSQLFORM_H
diff --git a/src/sql/qsqlindex.cpp b/src/sql/qsqlindex.cpp
new file mode 100644
index 000000000..251e9ef28
--- /dev/null
+++ b/src/sql/qsqlindex.cpp
@@ -0,0 +1,301 @@
+/****************************************************************************
+**
+** Implementation of TQSqlIndex class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlIndex qsqlindex.h
+ \brief The TQSqlIndex class provides functions to manipulate and
+ describe TQSqlCursor and TQSqlDatabase indexes.
+
+ \ingroup database
+ \module sql
+
+ This class is used to describe and manipulate TQSqlCursor and
+ TQSqlDatabase 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 TQSqlCursor object.
+
+ Normally, TQSqlIndex objects are created by \l TQSqlDatabase or
+ TQSqlCursor.
+*/
+
+/*!
+ Constructs an empty index using the cursor name \a cursorname and
+ index name \a name.
+*/
+
+TQSqlIndex::TQSqlIndex( const TQString& cursorname, const TQString& name )
+ : TQSqlRecord(), cursor(cursorname), nm(name)
+{
+
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+
+TQSqlIndex::TQSqlIndex( const TQSqlIndex& other )
+ : TQSqlRecord(other), cursor(other.cursor), nm(other.nm), sorts(other.sorts)
+{
+}
+
+/*!
+ Sets the index equal to \a other.
+*/
+
+TQSqlIndex& TQSqlIndex::operator=( const TQSqlIndex& other )
+{
+ cursor = other.cursor;
+ nm = other.nm;
+ sorts = other.sorts;
+ TQSqlRecord::operator=( other );
+ return *this;
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQSqlIndex::~TQSqlIndex()
+{
+
+}
+
+/*!
+ Sets the name of the index to \a name.
+*/
+
+void TQSqlIndex::setName( const TQString& name )
+{
+ nm = name;
+}
+
+/*!
+ \fn TQString TQSqlIndex::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 TQSqlIndex::append( const TQSqlField& 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 TQSqlIndex::append( const TQSqlField& field, bool desc )
+{
+ sorts.append( desc );
+ TQSqlRecord::append( field );
+}
+
+
+/*!
+ Returns TRUE if field \a i in the index is sorted in descending
+ order; otherwise returns FALSE.
+*/
+
+bool TQSqlIndex::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 TQSqlIndex::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.
+*/
+
+TQString TQSqlIndex::toString( const TQString& prefix, const TQString& sep, bool verbose ) const
+{
+ TQString 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
+ TQStringList list = myIndex.toStringList();
+ TQStringList::Iterator it = list.begin();
+ while( it != list.end() ) {
+ myProcessing( *it );
+ ++it;
+ }
+ \endcode
+
+*/
+TQStringList TQSqlIndex::toStringList( const TQString& prefix, bool verbose ) const
+{
+ TQStringList 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.
+*/
+
+TQString TQSqlIndex::createField( int i, const TQString& prefix, bool verbose ) const
+{
+ TQString f;
+ if ( !prefix.isEmpty() )
+ f += prefix + ".";
+ f += field( i )->name();
+ if ( verbose )
+ f += " " + TQString( ( 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()
+*/
+
+TQSqlIndex TQSqlIndex::fromStringList( const TQStringList& l, const TQSqlCursor* cursor )
+{
+ TQSqlIndex newSort;
+ for ( uint i = 0; i < l.count(); ++i ) {
+ TQString 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 TQSqlField* field = cursor->field( f.simplifyWhiteSpace() );
+ if ( field )
+ newSort.append( *field, desc );
+ else
+ qWarning( "TQSqlIndex::fromStringList: unknown field: '%s'", f.latin1());
+ }
+ return newSort;
+}
+
+/*!
+ \fn TQString TQSqlIndex::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 TQSqlIndex::setCursorName( const TQString& cursorName )
+{
+ cursor = cursorName;
+}
+
+#endif
diff --git a/src/sql/qsqlindex.h b/src/sql/qsqlindex.h
new file mode 100644
index 000000000..9985053bc
--- /dev/null
+++ b/src/sql/qsqlindex.h
@@ -0,0 +1,99 @@
+/****************************************************************************
+**
+** Definition of TQSqlIndex class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLINDEX_H
+#define TQSQLINDEX_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 TQM_EXPORT_SQL
+#define TQM_TEMPLATE_EXTERN_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#define TQM_TEMPLATE_EXTERN_SQL Q_TEMPLATE_EXTERN
+#endif
+
+#ifndef QT_NO_SQL
+
+class TQSqlCursor;
+
+class TQM_EXPORT_SQL TQSqlIndex : public TQSqlRecord
+{
+public:
+ TQSqlIndex( const TQString& cursorName = TQString::null, const TQString& name = TQString::null );
+ TQSqlIndex( const TQSqlIndex& other );
+ ~TQSqlIndex();
+ TQSqlIndex& operator=( const TQSqlIndex& other );
+ virtual void setCursorName( const TQString& cursorName );
+ TQString cursorName() const { return cursor; }
+ virtual void setName( const TQString& name );
+ TQString name() const { return nm; }
+
+ void append( const TQSqlField& field );
+ virtual void append( const TQSqlField& field, bool desc );
+
+ bool isDescending( int i ) const;
+ virtual void setDescending( int i, bool desc );
+
+ TQString toString( const TQString& prefix = TQString::null,
+ const TQString& sep = ",",
+ bool verbose = TRUE ) const;
+ TQStringList toStringList( const TQString& prefix = TQString::null,
+ bool verbose = TRUE ) const;
+
+ static TQSqlIndex fromStringList( const TQStringList& l, const TQSqlCursor* cursor );
+
+private:
+ TQString createField( int i, const TQString& prefix, bool verbose ) const;
+ TQString cursor;
+ TQString nm;
+ TQValueList<bool> sorts;
+};
+
+#define Q_DEFINED_QSQLINDEX
+#include "qwinexport.h"
+#endif // QT_NO_SQL
+#endif
diff --git a/src/sql/qsqlmanager_p.cpp b/src/sql/qsqlmanager_p.cpp
new file mode 100644
index 000000000..100512623
--- /dev/null
+++ b/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 TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlCursorManagerPrivate
+{
+public:
+ TQSqlCursorManagerPrivate()
+ : cur( 0 ), autoDelete( FALSE )
+ {}
+
+ TQString ftr;
+ TQStringList srt;
+ TQSqlCursor* cur;
+ bool autoDelete;
+};
+
+/*!
+ \class TQSqlCursorManager qsqlmanager_p.h
+ \brief The TQSqlCursorManager 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.
+
+*/
+
+TQSqlCursorManager::TQSqlCursorManager()
+{
+ d = new TQSqlCursorManagerPrivate;
+}
+
+
+/*! \internal
+
+ Destroys the object and frees any allocated resources.
+
+*/
+
+TQSqlCursorManager::~TQSqlCursorManager()
+{
+ 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 TQSqlCursorManager::setSort( const TQSqlIndex& sort )
+{
+ setSort( sort.toStringList() );
+}
+
+/*! \internal
+
+ Sets the manager's sort to the stringlist \a sort. To apply the
+ new sort, use refresh().
+
+ */
+
+void TQSqlCursorManager::setSort( const TQStringList& sort )
+{
+ d->srt = sort;
+}
+
+/*! \internal
+
+ Returns the current sort, or an empty stringlist if there is none.
+
+*/
+
+TQStringList TQSqlCursorManager::sort() const
+{
+ return d->srt;
+}
+
+/*! \internal
+
+ Sets the manager's filter to the string \a filter. To apply the
+ new filter, use refresh().
+
+*/
+
+void TQSqlCursorManager::setFilter( const TQString& filter )
+{
+ d->ftr = filter;
+}
+
+/*! \internal
+
+ Returns the current filter, or an empty string if there is none.
+
+*/
+
+TQString TQSqlCursorManager::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 TQSqlCursorManager::setAutoDelete( bool enable )
+{
+ d->autoDelete = enable;
+}
+
+
+/*! \internal
+
+ Returns TRUE if auto-deletion is enabled, otherwise FALSE.
+
+ \sa setAutoDelete()
+
+*/
+
+bool TQSqlCursorManager::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 TQSqlCursorManager::setCursor( TQSqlCursor* 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()
+
+*/
+
+TQSqlCursor* TQSqlCursorManager::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 TQSqlCursorManager::refresh()
+{
+ TQSqlCursor* cur = cursor();
+ if ( !cur )
+ return FALSE;
+ TQString currentFilter = d->ftr;
+ TQStringList currentSort = d->srt;
+ TQSqlIndex newSort = TQSqlIndex::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 TQSqlCursor* cur, const TQSqlRecord* buf,
+ const TQSqlIndex& idx )
+{
+ bool indexEquals = FALSE;
+ for ( uint i = 0; i < idx.count(); ++i ) {
+ const TQString 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 TQSqlRecord* buf1, const TQSqlRecord* buf2,
+ const TQSqlIndex& idx )
+{
+ int cmp = 0;
+
+ int i = 0;
+ const TQString fn( idx.field(i)->name() );
+ const TQSqlField* f1 = buf1->field( fn );
+
+ if ( f1 ) {
+ switch ( f1->type() ) { // ### more types?
+ case TQVariant::String:
+ case TQVariant::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 TQString& msg, TQSqlRecord* cursor )
+{
+ qDebug("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++");
+ qDebug( "%s", msg.latin1() );
+ for ( uint j = 0; j < cursor->count(); ++j ) {
+ qDebug( "%s", (cursor->field(j)->name() + " type:"
+ + TQString(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
+ TQSqlCursor* myCursor = myManager.cursor();
+ ...
+ TQSqlRecord* 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 TQSqlCursorManager::findBuffer( const TQSqlIndex& idx, int atHint )
+{
+#ifdef QT_DEBUG_DATAMANAGER
+ qDebug("TQSqlCursorManager::findBuffer:");
+#endif
+ TQSqlCursor* cur = cursor();
+ if ( !cur )
+ return FALSE;
+ if ( !cur->isActive() )
+ return FALSE;
+ if ( !idx.count() ) {
+ if ( cur->at() == TQSql::BeforeFirst )
+ cur->next();
+ return FALSE;
+ }
+ TQSqlRecord* 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 = TQMAX( 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( TQSqlDriver::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
+ TQApplication::setOverrideCursor( TQt::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
+ TQApplication::restoreOverrideCursor();
+#endif
+ }
+#ifdef QT_DEBUG_DATAMANAGER
+ qDebug(" Done, result:" + TQString::number( indexEquals ) );
+#endif
+ return indexEquals;
+}
+
+#ifndef QT_NO_SQL_FORM
+
+class TQSqlFormManagerPrivate
+{
+public:
+ TQSqlFormManagerPrivate() : frm(0), rcd(0) {}
+ TQSqlForm* frm;
+ TQSqlRecord* rcd;
+};
+
+
+/*! \internal
+
+ Creates a form manager.
+
+*/
+
+TQSqlFormManager::TQSqlFormManager()
+{
+ d = new TQSqlFormManagerPrivate();
+}
+
+/*! \internal
+
+ Destroys the object and frees any allocated resources.
+
+*/
+
+TQSqlFormManager::~TQSqlFormManager()
+{
+ delete d;
+}
+
+/*! \internal
+
+ Clears the default form values. If there is no default form,
+ nothing happens,
+
+*/
+
+void TQSqlFormManager::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 TQSqlFormManager::setForm( TQSqlForm* 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()
+
+*/
+
+TQSqlForm* TQSqlFormManager::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 TQSqlFormManager::setRecord( TQSqlRecord* 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()
+*/
+
+TQSqlRecord* TQSqlFormManager::record()
+{
+ return d->rcd;
+}
+
+
+/*! \internal
+
+ Causes the default form to read its fields . If there is no
+ default form, nothing happens.
+
+ \sa setForm()
+
+*/
+
+void TQSqlFormManager::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 TQSqlFormManager::writeFields()
+{
+ if ( d->frm ) {
+ d->frm->writeFields();
+ }
+}
+
+#endif // QT_NO_SQL_FORM
+
+class TQDataManagerPrivate
+{
+public:
+ TQDataManagerPrivate()
+ : mode( TQSql::None ), autoEd( TRUE ), confEdits( 3 ),
+ confCancs( FALSE ) {}
+ TQSql::Op mode;
+ bool autoEd;
+ TQBitArray confEdits;
+ bool confCancs;
+
+};
+
+/*!
+ \class TQDataManager qsqlmanager_p.h
+ \ingroup database
+
+ \brief The TQDataManager class is an internal class for implementing
+ the data-aware widgets.
+
+ \internal
+
+ TQDataManager is a strictly internal class that acts as a base class
+ for other data-aware widgets.
+
+*/
+
+
+/*! \internal
+
+ Constructs an empty data handler.
+
+*/
+
+TQDataManager::TQDataManager()
+{
+ d = new TQDataManagerPrivate();
+}
+
+
+/*! \internal
+
+ Destroys the object and frees any allocated resources.
+
+*/
+
+TQDataManager::~TQDataManager()
+{
+ 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 TQDataManager::handleError( TQWidget* parent, const TQSqlError& e )
+{
+#ifndef QT_NO_MESSAGEBOX
+ if (e.driverText().isEmpty() && e.databaseText().isEmpty()) {
+ TQMessageBox::warning ( parent, "Warning", "An error occurred while accessing the database");
+ } else {
+ TQMessageBox::warning ( parent, "Warning", e.driverText() + "\n" + e.databaseText(),
+ 0, 0 );
+ }
+#endif // QT_NO_MESSAGEBOX
+}
+
+
+/*! \internal
+
+ Sets the internal mode to \a m.
+
+*/
+
+void TQDataManager::setMode( TQSql::Op m )
+{
+ d->mode = m;
+}
+
+
+/*! \internal
+
+ Returns the current mode.
+
+*/
+
+TQSql::Op TQDataManager::mode() const
+{
+ return d->mode;
+}
+
+
+/*! \internal
+
+ Sets the auto-edit mode to \a auto.
+
+*/
+
+void TQDataManager::setAutoEdit( bool autoEdit )
+{
+ d->autoEd = autoEdit;
+}
+
+
+
+/*! \internal
+
+ Returns TRUE if auto-edit mode is enabled; otherwise returns FALSE.
+
+*/
+
+bool TQDataManager::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 TQDataManager::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 TQDataManager::setConfirmInsert( bool confirm )
+{
+ d->confEdits[ TQSql::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 TQDataManager::setConfirmUpdate( bool confirm )
+{
+ d->confEdits[ TQSql::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 TQDataManager::setConfirmDelete( bool confirm )
+{
+ d->confEdits[ TQSql::Delete ] = confirm;
+}
+
+/*! \internal
+
+ Returns TRUE if the table confirms all edit operations (inserts,
+ updates and deletes), otherwise returns FALSE.
+*/
+
+bool TQDataManager::confirmEdits() const
+{
+ return ( confirmInsert() && confirmUpdate() && confirmDelete() );
+}
+
+/*! \internal
+
+ Returns TRUE if the table confirms inserts, otherwise returns
+ FALSE.
+*/
+
+bool TQDataManager::confirmInsert() const
+{
+ return d->confEdits[ TQSql::Insert ];
+}
+
+/*! \internal
+
+ Returns TRUE if the table confirms updates, otherwise returns
+ FALSE.
+*/
+
+bool TQDataManager::confirmUpdate() const
+{
+ return d->confEdits[ TQSql::Update ];
+}
+
+/*! \internal
+
+ Returns TRUE if the table confirms deletes, otherwise returns
+ FALSE.
+*/
+
+bool TQDataManager::confirmDelete() const
+{
+ return d->confEdits[ TQSql::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 TQDataManager::setConfirmCancels( bool confirm )
+{
+ d->confCancs = confirm;
+}
+
+/*! \internal
+
+ Returns TRUE if the table confirms cancels, otherwise returns FALSE.
+*/
+
+bool TQDataManager::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.
+
+*/
+
+TQSql::Confirm TQDataManager::confirmEdit( TQWidget* parent, TQSql::Op m )
+{
+ int ans = 2;
+ if ( m == TQSql::Delete ) {
+#ifndef QT_NO_MESSAGEBOX
+ ans = TQMessageBox::information( parent,
+ qApp->translate( "TQSql", "Delete" ),
+ qApp->translate( "TQSql", "Delete this record?" ),
+ qApp->translate( "TQSql", "Yes" ),
+ qApp->translate( "TQSql", "No" ),
+ TQString::null, 0, 1 );
+#else
+ ans = TQSql::No;
+#endif // QT_NO_MESSAGEBOX
+ } else if ( m != TQSql::None ) {
+ TQString caption;
+ if ( m == TQSql::Insert ) {
+ caption = qApp->translate( "TQSql", "Insert" );
+ } else { // TQSql::Update
+ caption = qApp->translate( "TQSql", "Update" );
+ }
+#ifndef QT_NO_MESSAGEBOX
+ ans = TQMessageBox::information( parent, caption,
+ qApp->translate( "TQSql", "Save edits?" ),
+ qApp->translate( "TQSql", "Yes" ),
+ qApp->translate( "TQSql", "No" ),
+ qApp->translate( "TQSql", "Cancel" ),
+ 0, 2 );
+#else
+ ans = TQSql::No;
+#endif // QT_NO_MESSAGEBOX
+ }
+
+ switch ( ans ) {
+ case 0:
+ return TQSql::Yes;
+ case 1:
+ return TQSql::No;
+ default:
+ return TQSql::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.
+
+
+*/
+
+TQSql::Confirm TQDataManager::confirmCancel( TQWidget* parent, TQSql::Op )
+{
+#ifndef QT_NO_MESSAGEBOX
+ switch ( TQMessageBox::information( parent,
+ qApp->translate( "TQSql", "Confirm" ),
+ qApp->translate( "TQSql", "Cancel your edits?" ),
+ qApp->translate( "TQSql", "Yes" ),
+ qApp->translate( "TQSql", "No" ),
+ TQString::null, 0, 1 ) ) {
+ case 0:
+ return TQSql::Yes;
+ case 1:
+ return TQSql::No;
+ default:
+ return TQSql::Cancel;
+ }
+#else
+ return TQSql::Yes;
+#endif // QT_NO_MESSAGEBOX
+}
+
+#endif
diff --git a/src/sql/qsqlmanager_p.h b/src/sql/qsqlmanager_p.h
new file mode 100644
index 000000000..660e4dded
--- /dev/null
+++ b/src/sql/qsqlmanager_p.h
@@ -0,0 +1,163 @@
+/****************************************************************************
+**
+** Definition of TQSqlManager class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLMANAGER_P_H
+#define TQSQLMANAGER_P_H
+
+//
+// W A R N I N G
+// -------------
+//
+// This file is not part of the TQt API. It exists for the convenience
+// of other TQt 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 TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL
+
+class TQSqlCursor;
+class TQSqlForm;
+class TQSqlCursorManagerPrivate;
+
+class TQM_EXPORT_SQL TQSqlCursorManager
+{
+public:
+ TQSqlCursorManager();
+ virtual ~TQSqlCursorManager();
+
+ virtual void setSort( const TQSqlIndex& sort );
+ virtual void setSort( const TQStringList& sort );
+ TQStringList sort() const;
+ virtual void setFilter( const TQString& filter );
+ TQString filter() const;
+ virtual void setCursor( TQSqlCursor* cursor, bool autoDelete = FALSE );
+ TQSqlCursor* cursor() const;
+
+ virtual void setAutoDelete( bool enable );
+ bool autoDelete() const;
+
+ virtual bool refresh();
+ virtual bool findBuffer( const TQSqlIndex& idx, int atHint = 0 );
+
+private:
+ TQSqlCursorManagerPrivate* d;
+};
+
+#ifndef QT_NO_SQL_FORM
+
+class TQSqlFormManagerPrivate;
+
+class TQM_EXPORT_SQL TQSqlFormManager
+{
+public:
+ TQSqlFormManager();
+ virtual ~TQSqlFormManager();
+
+ virtual void setForm( TQSqlForm* form );
+ TQSqlForm* form();
+ virtual void setRecord( TQSqlRecord* record );
+ TQSqlRecord* record();
+
+ virtual void clearValues();
+ virtual void readFields();
+ virtual void writeFields();
+
+private:
+ TQSqlFormManagerPrivate* d;
+};
+
+#endif
+
+class TQWidget;
+class TQDataManagerPrivate;
+
+class TQM_EXPORT_SQL TQDataManager
+{
+public:
+ TQDataManager();
+ virtual ~TQDataManager();
+
+ virtual void setMode( TQSql::Op m );
+ TQSql::Op mode() const;
+ virtual void setAutoEdit( bool autoEdit );
+ bool autoEdit() const;
+
+ virtual void handleError( TQWidget* parent, const TQSqlError& error );
+ virtual TQSql::Confirm confirmEdit( TQWidget* parent, TQSql::Op m );
+ virtual TQSql::Confirm confirmCancel( TQWidget* parent, TQSql::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:
+ TQDataManagerPrivate* d;
+};
+
+
+#endif
+#endif
diff --git a/src/sql/qsqlpropertymap.cpp b/src/sql/qsqlpropertymap.cpp
new file mode 100644
index 000000000..55699e569
--- /dev/null
+++ b/src/sql/qsqlpropertymap.cpp
@@ -0,0 +1,304 @@
+/****************************************************************************
+**
+** Definition of TQSqlPropertyMap class
+**
+** Created : 2000-11-20
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlPropertyMapPrivate
+{
+public:
+ TQSqlPropertyMapPrivate() {}
+ TQMap< TQString, TQString > propertyMap;
+};
+
+/*!
+ \class TQSqlPropertyMap qsqlpropertymap.h
+ \brief The TQSqlPropertyMap class is used to map widgets to SQL fields.
+
+ \ingroup database
+ \module sql
+
+ The SQL module uses TQt \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 TQLineEdit can be used to edit text strings and
+ other data types in TQDataTables or TQSqlForms. Several properties
+ are defined in TQLineEdit, but only the \e text property is used to
+ insert and extract text from a TQLineEdit. Both TQDataTable and
+ TQSqlForm use the global TQSqlPropertyMap 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 TQDataTable or
+ TQSqlForm, you must install your own TQSqlPropertyMap for that table
+ or form. Example:
+
+ \code
+ TQSqlPropertyMap *myMap = new TQSqlPropertyMap();
+ TQSqlForm *myForm = new TQSqlForm( this );
+ MyEditor myEditor( this );
+
+ // Set the TQSqlForm's record buffer to the update buffer of
+ // a pre-existing TQSqlCursor 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 TQSqlPropertyMap that is used by
+ default. (Bear in mind that TQSqlPropertyMap takes ownership of the
+ new default map.)
+
+ \code
+ TQSqlPropertyMap *myMap = new TQSqlPropertyMap;
+
+ myMap->insert( "MyEditor", "content" );
+ TQSqlPropertyMap::installDefaultMap( myMap );
+ ...
+ \endcode
+
+ \sa TQDataTable, TQSqlForm, TQSqlEditorFactory
+*/
+
+/*!
+
+Constructs a TQSqlPropertyMap.
+
+The default property mappings used by TQt widgets are:
+\table
+\header \i Widgets \i Property
+\row \i \l TQCheckBox,
+ \l TQRadioButton
+ \i checked
+\row \i \l TQComboBox,
+ \l TQListBox
+ \i currentItem
+\row \i \l TQDateEdit
+ \i date
+\row \i \l TQDateTimeEdit
+ \i dateTime
+\row \i \l TQTextBrowser
+ \i source
+\row \i \l TQButton,
+ \l TQDial,
+ \l TQLabel,
+ \l TQLineEdit,
+ \l TQMultiLineEdit,
+ \l TQPushButton,
+ \l TQTextEdit,
+ \i text
+\row \i \l TQTimeEdit
+ \i time
+\row \i \l TQLCDNumber,
+ \l TQScrollBar
+ \l TQSlider,
+ \l TQSpinBox
+ \i value
+\endtable
+*/
+
+TQSqlPropertyMap::TQSqlPropertyMap()
+{
+ d = new TQSqlPropertyMapPrivate();
+ const struct MapData {
+ const char *classname;
+ const char *property;
+ } mapData[] = {
+ { "TQButton", "text" },
+ { "TQCheckBox", "checked" },
+ { "TQRadioButton", "checked" },
+ { "TQComboBox", "currentItem" },
+ { "TQDateEdit", "date" },
+ { "TQDateTimeEdit", "dateTime" },
+ { "TQDial", "value" },
+ { "TQLabel", "text" },
+ { "TQLCDNumber", "value" },
+ { "TQLineEdit", "text" },
+ { "TQListBox", "currentItem" },
+ { "TQMultiLineEdit", "text" },
+ { "TQPushButton", "text" },
+ { "TQScrollBar", "value" },
+ { "TQSlider", "value" },
+ { "TQSpinBox", "value" },
+ { "TQTextBrowser", "source" },
+ { "TQTextEdit", "text" },
+ { "TQTextView", "text" },
+ { "TQTimeEdit", "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 TQSqlPropertyMap.
+
+ Note that if the TQSqlPropertyMap is installed with
+ installPropertyMap() the object it was installed into, e.g. the
+ TQSqlForm, takes ownership and will delete the TQSqlPropertyMap when
+ necessary.
+*/
+TQSqlPropertyMap::~TQSqlPropertyMap()
+{
+ delete d;
+}
+
+/*!
+ Returns the mapped property of \a widget as a TQVariant.
+*/
+TQVariant TQSqlPropertyMap::property( TQWidget * widget )
+{
+ if( !widget ) return TQVariant();
+ const TQMetaObject* mo = widget->metaObject();
+ while ( mo && !d->propertyMap.contains( TQString( mo->className() ) ) )
+ mo = mo->superClass();
+
+ if ( !mo ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQSqlPropertyMap::property: %s does not exist", widget->metaObject()->className() );
+#endif
+ return TQVariant();
+ }
+ return widget->property( d->propertyMap[ mo->className() ] );
+}
+
+/*!
+ Sets the property of \a widget to \a value.
+*/
+void TQSqlPropertyMap::setProperty( TQWidget * widget, const TQVariant & value )
+{
+ if( !widget ) return;
+
+ TQMetaObject* mo = widget->metaObject();
+ while ( mo && !d->propertyMap.contains( TQString( mo->className() ) ) )
+ mo = mo->superClass();
+ if ( !mo ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQSqlPropertyMap::setProperty: %s not handled by TQSqlPropertyMap", 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 TQSqlPropertyMap::insert( const TQString & classname,
+ const TQString & property )
+{
+ d->propertyMap[ classname ] = property;
+}
+
+/*!
+ Removes \a classname from the map.
+*/
+void TQSqlPropertyMap::remove( const TQString & classname )
+{
+ d->propertyMap.remove( classname );
+}
+
+static TQSqlPropertyMap * defaultmap = 0;
+static TQCleanupHandler< TQSqlPropertyMap > qsql_cleanup_property_map;
+
+/*!
+ Returns the application global TQSqlPropertyMap.
+*/
+TQSqlPropertyMap * TQSqlPropertyMap::defaultMap()
+{
+ if( defaultmap == 0 ){
+ defaultmap = new TQSqlPropertyMap();
+ qsql_cleanup_property_map.add( &defaultmap );
+ }
+ return defaultmap;
+}
+
+/*!
+ Replaces the global default property map with \a map. All
+ TQDataTable and TQSqlForm instantiations will use this new map for
+ inserting and extracting values to and from editors.
+ \e{TQSqlPropertyMap takes ownership of \a map, and destroys it
+ when it is no longer needed.}
+*/
+void TQSqlPropertyMap::installDefaultMap( TQSqlPropertyMap * 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/src/sql/qsqlpropertymap.h b/src/sql/qsqlpropertymap.h
new file mode 100644
index 000000000..a326475d5
--- /dev/null
+++ b/src/sql/qsqlpropertymap.h
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Definition of TQSqlPropertyMap class
+**
+** Created : 2000-11-20
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLPROPERTYMAP_H
+#define TQSQLPROPERTYMAP_H
+
+#ifndef QT_H
+#include "qvariant.h"
+#include "qstring.h"
+#endif // QT_H
+
+#ifndef QT_NO_SQL_FORM
+
+class TQWidget;
+class TQSqlPropertyMapPrivate;
+
+class Q_EXPORT TQSqlPropertyMap {
+public:
+ TQSqlPropertyMap();
+ virtual ~TQSqlPropertyMap();
+
+ TQVariant property( TQWidget * widget );
+ virtual void setProperty( TQWidget * widget, const TQVariant & value );
+
+ void insert( const TQString & classname, const TQString & property );
+ void remove( const TQString & classname );
+
+ static TQSqlPropertyMap * defaultMap();
+ static void installDefaultMap( TQSqlPropertyMap * map );
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ TQSqlPropertyMap( const TQSqlPropertyMap & );
+ TQSqlPropertyMap &operator=( const TQSqlPropertyMap & );
+#endif
+ TQSqlPropertyMapPrivate* d;
+
+};
+
+#endif // QT_NO_SQL_FORM
+#endif // TQSQLPROPERTYMAP_H
diff --git a/src/sql/qsqlquery.cpp b/src/sql/qsqlquery.cpp
new file mode 100644
index 000000000..c33eb8bf2
--- /dev/null
+++ b/src/sql/qsqlquery.cpp
@@ -0,0 +1,1215 @@
+/****************************************************************************
+**
+** Implementation of TQSqlQuery class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2000-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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
+*/
+TQSqlResultShared::TQSqlResultShared( TQSqlResult* result ): sqlResult(result)
+{
+ if ( result )
+ connect( result->driver(), SIGNAL(destroyed()), this, SLOT(slotResultDestroyed()) );
+}
+
+/*!
+\internal
+*/
+TQSqlResultShared::~TQSqlResultShared()
+{
+ delete sqlResult;
+}
+
+/*!
+\internal
+
+In case a plugin gets unloaded the pointer to the sqlResult gets invalid
+*/
+void TQSqlResultShared::slotResultDestroyed()
+{
+ delete sqlResult;
+ sqlResult = 0;
+}
+
+/*!
+ \class TQSqlQuery qsqlquery.h
+ \brief The TQSqlQuery class provides a means of executing and
+ manipulating SQL statements.
+
+ \ingroup database
+ \mainclass
+ \module sql
+
+ TQSqlQuery encapsulates the functionality involved in creating,
+ navigating and retrieving data from SQL queries which are executed
+ on a \l TQSqlDatabase. 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 TQSqlQuery::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
+ TQVariants.
+
+ For example:
+
+ \code
+ TQSqlQuery query( "SELECT name FROM customer" );
+ while ( query.next() ) {
+ TQString 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 TQSqlDatabase::record().
+ For the sake of efficiency there are no functions to access a field
+ by name. (The \l TQSqlCursor class provides a higher-level interface
+ with field access by name and automatic SQL generation.)
+
+ TQSqlQuery supports prepared query execution and the binding of
+ parameter values to placeholders. Some databases don't support
+ these features, so for them TQt emulates the retquired
+ functionality. For example, the Oracle and ODBC drivers have
+ proper prepared query support, and TQt makes use of it; but for
+ databases that don't have this support, TQt 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 retquires 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. TQt
+ 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
+ TQSqlQuery 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
+ TQSqlQuery 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 TQSqlDriver::hasFeature() using TQSqlDriver::PreparedQueries
+ as argument for driver feature.
+
+ <b>Binding values using positional placeholders #1</b>
+ \code
+ TQSqlQuery 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
+ TQSqlQuery query;
+ query.prepare( "call AsciiToInt(?, ?)" );
+ query.bindValue( 0, "A" );
+ query.bindValue( 1, 0, TQSql::Out );
+ query.exec();
+ int i = query.boundValue( 1 ).toInt(); // i is 65.
+ \endcode
+
+ \sa TQSqlDatabase TQSqlCursor TQVariant
+*/
+
+/*!
+ Creates a TQSqlQuery object which uses the TQSqlResult \a r to
+ communicate with a database.
+*/
+
+TQSqlQuery::TQSqlQuery( TQSqlResult * r )
+{
+ d = new TQSqlResultShared( r );
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQSqlQuery::~TQSqlQuery()
+{
+ if (d->deref()) {
+ delete d;
+ }
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+
+TQSqlQuery::TQSqlQuery( const TQSqlQuery& other )
+ : d(other.d)
+{
+ d->ref();
+}
+
+/*!
+ Creates a TQSqlQuery 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 TQSqlDatabase
+*/
+TQSqlQuery::TQSqlQuery( const TQString& query, TQSqlDatabase* db )
+{
+ init( query, db );
+}
+
+/*!
+ Creates a TQSqlQuery object using the database \a db. If \a db is
+ 0, the application's default database is used.
+
+ \sa TQSqlDatabase
+*/
+
+TQSqlQuery::TQSqlQuery( TQSqlDatabase* db )
+{
+ init( TQString::null, db );
+}
+
+/*! \internal
+*/
+
+void TQSqlQuery::init( const TQString& query, TQSqlDatabase* db )
+{
+ d = new TQSqlResultShared( 0 );
+ TQSqlDatabase* database = db;
+ if ( !database )
+ database = TQSqlDatabase::database( TQSqlDatabase::defaultConnection, FALSE );
+ if ( database )
+ *this = database->driver()->createQuery();
+ if ( !query.isNull() )
+ exec( query );
+}
+
+/*!
+ Assigns \a other to the query.
+*/
+
+TQSqlQuery& TQSqlQuery::operator=( const TQSqlQuery& 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 TQSqlQuery::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 TQSqlQuery::exec ( const TQString& query )
+{
+ if ( !d->sqlResult )
+ return FALSE;
+ if ( d->sqlResult->extension() && driver()->hasFeature( TQSqlDriver::PreparedQueries ) )
+ d->sqlResult->extension()->clear();
+ d->sqlResult->setActive( FALSE );
+ d->sqlResult->setLastError( TQSqlError() );
+ d->sqlResult->setAt( TQSql::BeforeFirst );
+ if ( !driver() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQSqlQuery::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("TQSqlQuery::exec: database not open" );
+#endif
+ return FALSE;
+ }
+ if ( query.isNull() || query.length() == 0 ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQSqlQuery::exec: empty query" );
+#endif
+ return FALSE;
+ }
+#ifdef QT_DEBUG_SQL
+ qDebug( "\n TQSqlQuery: " + 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 TQVariant 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()
+*/
+
+TQVariant TQSqlQuery::value( int i ) const
+{
+ if ( !d->sqlResult )
+ return TQVariant();
+ if ( isActive() && isValid() && ( i > TQSql::BeforeFirst ) ) {
+ return d->sqlResult->data( i );
+ } else {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQSqlQuery::value: not positioned on a valid record" );
+#endif
+ }
+ return TQVariant();
+}
+
+/*!
+ Returns the current internal position of the query. The first
+ record is at position zero. If the position is invalid, a
+ TQSql::Location will be returned indicating the invalid position.
+
+ \sa prev() next() first() last() seek() isActive() isValid()
+*/
+
+int TQSqlQuery::at() const
+{
+ if ( !d->sqlResult )
+ return TQSql::BeforeFirst;
+ return d->sqlResult->at();
+}
+
+/*!
+ Returns the text of the current query being used, or TQString::null
+ if there is no current query text.
+
+ \sa executedQuery()
+*/
+
+TQString TQSqlQuery::lastQuery() const
+{
+ if ( !d->sqlResult )
+ return TQString::null;
+ return d->sqlResult->lastQuery();
+}
+
+/*!
+ Returns the database driver associated with the query.
+*/
+
+const TQSqlDriver* TQSqlQuery::driver() const
+{
+ if ( !d->sqlResult )
+ return 0;
+ return d->sqlResult->driver();
+}
+
+/*!
+ Returns the result associated with the query.
+*/
+
+const TQSqlResult* TQSqlQuery::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 TQSqlQuery::seek( int i, bool relative )
+{
+ if ( !isSelect() || !isActive() )
+ return FALSE;
+ beforeSeek();
+ checkDetach();
+ int actualIdx;
+ if ( !relative ) { // arbitrary seek
+ if ( i < 0 ) {
+ d->sqlResult->setAt( TQSql::BeforeFirst );
+ afterSeek();
+ return FALSE;
+ }
+ actualIdx = i;
+ } else {
+ switch ( at() ) { // relative seek
+ case TQSql::BeforeFirst:
+ if ( i > 0 )
+ actualIdx = i;
+ else {
+ afterSeek();
+ return FALSE;
+ }
+ break;
+ case TQSql::AfterLast:
+ if ( i < 0 ) {
+ d->sqlResult->fetchLast();
+ actualIdx = at() + i;
+ } else {
+ afterSeek();
+ return FALSE;
+ }
+ break;
+ default:
+ if ( ( at() + i ) < 0 ) {
+ d->sqlResult->setAt( TQSql::BeforeFirst );
+ afterSeek();
+ return FALSE;
+ }
+ actualIdx = at() + i;
+ break;
+ }
+ }
+ // let drivers optimize
+ if ( isForwardOnly() && actualIdx < at() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQSqlQuery::seek: cannot seek backwards in a forward only query" );
+#endif
+ afterSeek();
+ return FALSE;
+ }
+ if ( actualIdx == ( at() + 1 ) && at() != TQSql::BeforeFirst ) {
+ if ( !d->sqlResult->fetchNext() ) {
+ d->sqlResult->setAt( TQSql::AfterLast );
+ afterSeek();
+ return FALSE;
+ }
+ afterSeek();
+ return TRUE;
+ }
+ if ( actualIdx == ( at() - 1 ) ) {
+ if ( !d->sqlResult->fetchPrev() ) {
+ d->sqlResult->setAt( TQSql::BeforeFirst );
+ afterSeek();
+ return FALSE;
+ }
+ afterSeek();
+ return TRUE;
+ }
+ if ( !d->sqlResult->fetch( actualIdx ) ) {
+ d->sqlResult->setAt( TQSql::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 TQSqlQuery::next()
+{
+ if ( !isSelect() || !isActive() )
+ return FALSE;
+ beforeSeek();
+ checkDetach();
+ bool b = FALSE;
+ switch ( at() ) {
+ case TQSql::BeforeFirst:
+ b = d->sqlResult->fetchFirst();
+ afterSeek();
+ return b;
+ case TQSql::AfterLast:
+ afterSeek();
+ return FALSE;
+ default:
+ if ( !d->sqlResult->fetchNext() ) {
+ d->sqlResult->setAt( TQSql::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 TQSqlQuery::prev()
+{
+ if ( !isSelect() || !isActive() )
+ return FALSE;
+ if ( isForwardOnly() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQSqlQuery::seek: cannot seek backwards in a forward only query" );
+#endif
+ return FALSE;
+ }
+
+ beforeSeek();
+ checkDetach();
+ bool b = FALSE;
+ switch ( at() ) {
+ case TQSql::BeforeFirst:
+ afterSeek();
+ return FALSE;
+ case TQSql::AfterLast:
+ b = d->sqlResult->fetchLast();
+ afterSeek();
+ return b;
+ default:
+ if ( !d->sqlResult->fetchPrev() ) {
+ d->sqlResult->setAt( TQSql::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 TQSqlQuery::first()
+{
+ if ( !isSelect() || !isActive() )
+ return FALSE;
+ if ( isForwardOnly() && at() > TQSql::BeforeFirst ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQSqlQuery::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 TQSqlQuery::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() TQSqlDriver::hasFeature()
+*/
+int TQSqlQuery::size() const
+{
+ if ( !d->sqlResult )
+ return -1;
+ if ( isActive() && d->sqlResult->driver()->hasFeature( TQSqlDriver::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() TQSqlDriver::hasFeature()
+*/
+
+int TQSqlQuery::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 TQSqlError
+*/
+
+TQSqlError TQSqlQuery::lastError() const
+{
+ if ( !d->sqlResult )
+ return TQSqlError();
+ return d->sqlResult->lastError();
+}
+
+/*!
+ Returns TRUE if the query is currently positioned on a valid
+ record; otherwise returns FALSE.
+*/
+
+bool TQSqlQuery::isValid() const
+{
+ if ( !d->sqlResult )
+ return FALSE;
+ return d->sqlResult->isValid();
+}
+
+/*!
+ Returns TRUE if the query is currently active; otherwise returns
+ FALSE.
+*/
+
+bool TQSqlQuery::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 TQSqlQuery::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 TQSqlQuery::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
+ TQDataTable, since they must to be able to scroll backward as well
+ as forward.
+
+ \sa isForwardOnly(), next(), seek()
+*/
+void TQSqlQuery::setForwardOnly( bool forward )
+{
+ if ( d->sqlResult )
+ d->sqlResult->setForwardOnly( forward );
+}
+
+/*!
+ \internal
+*/
+
+void TQSqlQuery::deref()
+{
+ if ( d->deref() ) {
+ delete d;
+ d = 0;
+ }
+}
+
+/*!
+ \internal
+*/
+
+bool TQSqlQuery::checkDetach()
+{
+ if ( d->count > 1 && d->sqlResult ) {
+ TQString 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 TQSqlQuery::beforeSeek()
+{
+
+}
+
+
+/*!
+ Protected virtual function called after the internal record
+ pointer is moved to a new record. The default implementation does
+ nothing.
+*/
+
+void TQSqlQuery::afterSeek()
+{
+
+}
+
+// XXX: Hack to keep BCI - remove in 4.0. TQSqlExtension should be
+// removed, and the prepare(), exec() etc. fu's should be
+// made virtual members of TQSqlQuery/TQSqlResult
+
+/*!
+ 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 TQSqlQuery::prepare( const TQString& query )
+{
+ if ( !d->sqlResult || !d->sqlResult->extension() )
+ return FALSE;
+ d->sqlResult->setActive( FALSE );
+ d->sqlResult->setLastError( TQSqlError() );
+ d->sqlResult->setAt( TQSql::BeforeFirst );
+ d->sqlResult->extension()->clear();
+ if ( !driver() ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQSqlQuery::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("TQSqlQuery::prepare: database not open" );
+#endif
+ return FALSE;
+ }
+ if ( query.isNull() || query.length() == 0 ) {
+#ifdef QT_CHECK_RANGE
+ qWarning("TQSqlQuery::prepare: empty query" );
+#endif
+ return FALSE;
+ }
+#ifdef QT_DEBUG_SQL
+ qDebug( "\n TQSqlQuery: " + query );
+#endif
+ TQString q = query;
+ TQRegExp rx(TQString::fromLatin1("'[^']*'|:([a-zA-Z0-9_]+)"));
+ if ( driver()->hasFeature( TQSqlDriver::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( TQSqlDriver::NamedPlaceholders ) ) {
+ TQRegExp rx(TQString::fromLatin1("'[^']*'|\\?"));
+ while ( (i = rx.search( q, i )) != -1 ) {
+ if ( rx.cap(0) == "?" ) {
+ q = q.replace( i, 1, ":f" + TQString::number(cnt) );
+ cnt++;
+ }
+ i += rx.matchedLength();
+ }
+ } else if ( driver()->hasFeature( TQSqlDriver::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 TQSqlQuery::exec()
+{
+ bool ret;
+ if ( !d->sqlResult || !d->sqlResult->extension() )
+ return FALSE;
+ if ( driver()->hasFeature( TQSqlDriver::PreparedQueries ) ) {
+ ret = d->sqlResult->extension()->exec();
+ } else {
+ // fake preparation - just replace the placeholders..
+ TQString query = d->sqlResult->lastQuery();
+ if ( d->sqlResult->extension()->bindMethod() == TQSqlExtension::BindByName ) {
+ int i;
+ TQVariant val;
+ TQString 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;
+ TQSqlField 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 {
+ TQMap<int, TQString>::ConstIterator it;
+ TQString 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 ) {
+ TQSqlField 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..
+ TQString 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 TQSql::Out or \c TQSql::InOut, the placeholder will be
+ overwritten with data from the database after the exec() call.
+
+ \sa addBindValue(), prepare(), exec()
+*/
+void TQSqlQuery::bindValue( const TQString& placeholder, const TQVariant& val, TQSql::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 TQSql::Out or \c TQSql::InOut, the placeholder will be
+ overwritten with data from the database after the exec() call.
+
+ \sa addBindValue(), prepare(), exec()
+*/
+void TQSqlQuery::bindValue( int pos, const TQVariant& val, TQSql::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 TQSql::Out or \c TQSql::InOut, the placeholder will
+ be overwritten with data from the database after the exec() call.
+
+ \sa bindValue(), prepare(), exec()
+*/
+void TQSqlQuery::addBindValue( const TQVariant& val, TQSql::ParameterType type )
+{
+ if ( !d->sqlResult || !d->sqlResult->extension() )
+ return;
+ d->sqlResult->extension()->addBindValue( val, type );
+}
+
+
+/*!
+ \overload
+
+ Binds the placeholder with type \c TQSql::In.
+*/
+void TQSqlQuery::bindValue( const TQString& placeholder, const TQVariant& val )
+{
+ bindValue( placeholder, val, TQSql::In );
+}
+
+/*!
+ \overload
+
+ Binds the placeholder at position \a pos with type \c TQSql::In.
+*/
+void TQSqlQuery::bindValue( int pos, const TQVariant& val )
+{
+ bindValue( pos, val, TQSql::In );
+}
+
+/*!
+ \overload
+
+ Binds the placeholder with type \c TQSql::In.
+*/
+void TQSqlQuery::addBindValue( const TQVariant& val )
+{
+ addBindValue( val, TQSql::In );
+}
+
+/*!
+ Returns the value for the \a placeholder.
+*/
+TQVariant TQSqlQuery::boundValue( const TQString& placeholder ) const
+{
+ if ( !d->sqlResult || !d->sqlResult->extension() )
+ return TQVariant();
+ return d->sqlResult->extension()->boundValue( placeholder );
+}
+
+/*!
+ \overload
+
+ Returns the value for the placeholder at position \a pos.
+*/
+TQVariant TQSqlQuery::boundValue( int pos ) const
+{
+ if ( !d->sqlResult || !d->sqlResult->extension() )
+ return TQVariant();
+ return d->sqlResult->extension()->boundValue( pos );
+}
+
+/*!
+ Returns a map of the bound values.
+
+ The bound values can be examined in the following way:
+ \code
+ TQSqlQuery query;
+ ...
+ // Examine the bound values - bound using named binding
+ TQMap<TQString, TQVariant>::ConstIterator it;
+ TQMap<TQString, TQVariant> 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
+ TQValueList<TQVariant>::ConstIterator it;
+ TQValueList<TQVariant> list = query.boundValues().values();
+ int i = 0;
+ for ( it = list.begin(); it != list.end(); ++it )
+ qWarning( "Placeholder pos: %d, Value: " + (*it).toString(), i++ );
+ ...
+
+ \endcode
+*/
+TQMap<TQString,TQVariant> TQSqlQuery::boundValues() const
+{
+ if ( !d->sqlResult || !d->sqlResult->extension() )
+ return TQMap<TQString,TQVariant>();
+ 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()
+*/
+TQString TQSqlQuery::executedQuery() const
+{
+ return d->executedQuery;
+}
+#endif // QT_NO_SQL
diff --git a/src/sql/qsqlquery.h b/src/sql/qsqlquery.h
new file mode 100644
index 000000000..bc4efa7d9
--- /dev/null
+++ b/src/sql/qsqlquery.h
@@ -0,0 +1,133 @@
+/****************************************************************************
+**
+** Definition of TQSqlQuery class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLTQUERY_H
+#define TQSQLTQUERY_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 TQSqlDriver;
+class TQSqlResult;
+class TQSqlDatabase;
+
+class Q_EXPORT TQSqlResultShared : public TQObject, public TQShared
+{
+ Q_OBJECT
+public:
+ TQSqlResultShared( TQSqlResult* result );
+ virtual ~TQSqlResultShared();
+ TQSqlResult* sqlResult;
+ TQString executedQuery;
+private slots:
+ void slotResultDestroyed();
+};
+
+class Q_EXPORT TQSqlQuery
+{
+public:
+ TQSqlQuery( TQSqlResult * r );
+ TQSqlQuery( const TQString& query = TQString::null, TQSqlDatabase* db = 0 );
+ Q_EXPLICIT TQSqlQuery( TQSqlDatabase* db );
+ TQSqlQuery( const TQSqlQuery& other );
+ TQSqlQuery& operator=( const TQSqlQuery& other );
+ virtual ~TQSqlQuery();
+
+ bool isValid() const;
+ bool isActive() const;
+ bool isNull( int field ) const;
+ int at() const;
+ TQString lastQuery() const;
+ int numRowsAffected() const;
+ TQSqlError lastError() const;
+ bool isSelect() const;
+ int size() const;
+ const TQSqlDriver* driver() const;
+ const TQSqlResult* result() const;
+ bool isForwardOnly() const;
+ void setForwardOnly( bool forward );
+
+ virtual bool exec ( const TQString& query );
+ virtual TQVariant 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 TQString& query );
+ void bindValue( const TQString& placeholder, const TQVariant& val );
+ void bindValue( int pos, const TQVariant& val );
+ void addBindValue( const TQVariant& val );
+ // remove these overloads in 4.0
+ void bindValue( const TQString& placeholder, const TQVariant& val, TQSql::ParameterType type );
+ void bindValue( int pos, const TQVariant& val, TQSql::ParameterType type );
+ void addBindValue( const TQVariant& val, TQSql::ParameterType type );
+ TQVariant boundValue( const TQString& placeholder ) const;
+ TQVariant boundValue( int pos ) const;
+ TQMap<TQString, TQVariant> boundValues() const;
+ TQString executedQuery() const;
+
+protected:
+ virtual void beforeSeek();
+ virtual void afterSeek();
+
+private:
+ void init( const TQString& query, TQSqlDatabase* db );
+ void deref();
+ bool checkDetach();
+ TQSqlResultShared* d;
+};
+
+
+#endif // QT_NO_SQL
+#endif
diff --git a/src/sql/qsqlrecord.cpp b/src/sql/qsqlrecord.cpp
new file mode 100644
index 000000000..3bbe2d045
--- /dev/null
+++ b/src/sql/qsqlrecord.cpp
@@ -0,0 +1,774 @@
+/****************************************************************************
+**
+** Implementation of TQSqlRecord class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlRecordPrivate
+{
+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)
+ TQSqlField field;
+ bool nogen;
+ };
+
+ TQSqlRecordPrivate(): cnt(0)
+ {
+ }
+ TQSqlRecordPrivate( const TQSqlRecordPrivate& other )
+ {
+ *this = other;
+ }
+ ~TQSqlRecordPrivate() {};
+ TQSqlRecordPrivate& operator=( const TQSqlRecordPrivate& other )
+ {
+ fi = other.fi;
+ cnt = other.cnt;
+ return *this;
+ }
+ void append( const TQSqlField& field )
+ {
+ info i;
+ i.field = field;
+ fi.append( i );
+ cnt++;
+ }
+ void insert( int pos, const TQSqlField& 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:
+ TQValueVector< info > fi;
+ uint cnt;
+};
+
+TQSqlRecordShared::~TQSqlRecordShared()
+{
+ if ( d )
+ delete d;
+}
+
+/*!
+ \class TQSqlRecord qsqlfield.h
+ \brief The TQSqlRecord class encapsulates a database record, i.e. a
+ set of database fields.
+
+ \ingroup database
+ \module sql
+
+ The TQSqlRecord class encapsulates the functionality and
+ characteristics of a database record (usually a table or view within
+ the database). TQSqlRecords support adding and removing fields as
+ well as setting and retrieving field values.
+
+ TQSqlRecord is implicitly shared. This means you can make copies of
+ the record in time O(1). If multiple TQSqlRecord 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 TQSqlRecordInfo
+*/
+
+
+/*!
+ Constructs an empty record.
+*/
+
+TQSqlRecord::TQSqlRecord()
+{
+ sh = new TQSqlRecordShared( new TQSqlRecordPrivate() );
+}
+
+/*!
+ Constructs a copy of \a other.
+*/
+
+TQSqlRecord::TQSqlRecord( const TQSqlRecord& other )
+ : sh( other.sh )
+{
+ sh->ref();
+}
+
+/*!
+ Sets the record equal to \a other.
+*/
+
+TQSqlRecord& TQSqlRecord::operator=( const TQSqlRecord& other )
+{
+ other.sh->ref();
+ deref();
+ sh = other.sh;
+ return *this;
+}
+
+/*! \internal
+*/
+
+void TQSqlRecord::deref()
+{
+ if ( sh->deref() ) {
+ delete sh;
+ sh = 0;
+ }
+}
+
+/*! \internal
+*/
+
+bool TQSqlRecord::checkDetach()
+{
+ if ( sh->count > 1 ) {
+ sh->deref();
+ sh = new TQSqlRecordShared( new TQSqlRecordPrivate( *sh->d ) );
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQSqlRecord::~TQSqlRecord()
+{
+ 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{TQSqlQuery}s. When working
+ with a TQSqlCursor the \link TQSqlCursor::value() value(const
+ TQString&)\endlink overload which uses field names is more
+ appropriate.
+*/
+
+TQVariant TQSqlRecord::value( int i ) const
+{
+ const TQSqlField * f = field(i);
+
+ if( f )
+ return f->value();
+ return TQVariant();
+}
+
+/*!
+ \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.
+*/
+
+TQVariant TQSqlRecord::value( const TQString& name ) const
+{
+ const TQSqlField * f = field( name );
+
+ if( f )
+ return f->value();
+ return TQVariant();
+}
+
+/*!
+ Returns the name of the field at position \a i. If the field does
+ not exist, TQString::null is returned.
+*/
+
+TQString TQSqlRecord::fieldName( int i ) const
+{
+ const TQSqlField* f = field( i );
+ if ( f )
+ return f->name();
+ return TQString::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 TQSqlRecord::position( const TQString& name ) const
+{
+ for ( uint i = 0; i < count(); ++i ) {
+ if ( fieldName(i).upper() == name.upper() )
+ return i;
+ }
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQSqlRecord::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.
+*/
+
+TQSqlField* TQSqlRecord::field( int i )
+{
+ checkDetach();
+ if ( !sh->d->contains( i ) ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQSqlRecord::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.
+*/
+
+TQSqlField* TQSqlRecord::field( const TQString& name )
+{
+ checkDetach();
+ if ( !sh->d->contains( position( name ) ) )
+ return 0;
+ return &sh->d->fieldInfo( position( name ) )->field;
+}
+
+
+/*!
+ \overload
+*/
+
+const TQSqlField* TQSqlRecord::field( int i ) const
+{
+ if ( !sh->d->contains( i ) ) {
+#ifdef QT_CHECK_RANGE
+ qWarning( "TQSqlRecord::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 TQSqlField* TQSqlRecord::field( const TQString& 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 TQSqlRecord::append( const TQSqlField& 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 TQSqlRecord::insert( int pos, const TQSqlField& 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 TQSqlRecord::remove( int pos )
+{
+ checkDetach();
+ sh->d->remove( pos );
+}
+
+/*!
+ Removes all the record's fields.
+
+ \sa clearValues()
+*/
+
+void TQSqlRecord::clear()
+{
+ checkDetach();
+ sh->d->clear();
+}
+
+/*!
+ Returns TRUE if there are no fields in the record; otherwise
+ returns FALSE.
+*/
+
+bool TQSqlRecord::isEmpty() const
+{
+ return sh->d->isEmpty();
+}
+
+
+/*!
+ Returns TRUE if there is a field in the record called \a name;
+ otherwise returns FALSE.
+*/
+
+bool TQSqlRecord::contains( const TQString& 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 TQSqlRecord::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 TQSqlCursor.
+
+ \sa isGenerated()
+*/
+
+void TQSqlRecord::setGenerated( const TQString& name, bool generated )
+{
+ setGenerated( position( name ), generated );
+}
+
+/*!
+ \overload
+
+ Sets the generated flag for the field \a i to \a generated.
+
+ \sa isGenerated()
+*/
+
+void TQSqlRecord::setGenerated( int i, bool generated )
+{
+ checkDetach();
+ if ( !field( i ) )
+ return;
+ sh->d->fieldInfo( i )->nogen = !generated;
+}
+
+/*!
+ \internal
+ ### Remove in 4.0
+*/
+bool TQSqlRecord::isNull( int i )
+{
+ checkDetach();
+ TQSqlField* f = field( i );
+ if ( f ) {
+ return f->isNull();
+ }
+ return TRUE;
+}
+
+/*!
+ \internal
+ ### Remove in 4.0
+*/
+bool TQSqlRecord::isNull( const TQString& 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 TQSqlRecord::isNull( int i ) const
+{
+ const TQSqlField* 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 TQSqlRecord::isNull( const TQString& name ) const
+{
+ return isNull( position( name ) );
+}
+
+/*!
+ Sets the value of field \a i to NULL. If the field does not exist,
+ nothing happens.
+*/
+void TQSqlRecord::setNull( int i )
+{
+ checkDetach();
+ TQSqlField* 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 TQSqlRecord::setNull( const TQString& 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 TQSqlRecord::isGenerated( const TQString& 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 TQSqlRecord::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\>"
+*/
+
+TQString TQSqlRecord::toString( const TQString& prefix, const TQString& sep ) const
+{
+ TQString 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\>"
+*/
+
+TQStringList TQSqlRecord::toStringList( const TQString& prefix ) const
+{
+ TQStringList s;
+ for ( uint i = 0; i < count(); ++i ) {
+ if ( isGenerated( field(i)->name() ) )
+ s += createField( i, prefix );
+ }
+ return s;
+}
+
+/*! \internal
+*/
+
+TQString TQSqlRecord::createField( int i, const TQString& prefix ) const
+{
+ TQString f;
+ if ( !prefix.isEmpty() )
+ f = prefix + ".";
+ f += field( i )->name();
+ return f;
+}
+
+/*!
+ Returns the number of fields in the record.
+*/
+
+uint TQSqlRecord::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 TQSqlRecord::setValue( int i, const TQVariant& val )
+{
+ checkDetach();
+ TQSqlField* 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 TQSqlRecord::setValue( const TQString& name, const TQVariant& val )
+{
+ setValue( position( name ), val );
+}
+
+
+/******************************************/
+/******* TQSqlRecordInfo Impl ******/
+/******************************************/
+
+/*!
+ \class TQSqlRecordInfo qsqlrecord.h
+ \brief The TQSqlRecordInfo class encapsulates a set of database field meta data.
+
+ \ingroup database
+ \module sql
+
+ This class is a TQValueList 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 TQSqlFieldInfo record for a named
+ field.
+
+ \sa TQValueList, TQSqlFieldInfo
+*/
+
+
+/*!
+ Constructs a TQSqlRecordInfo object based on the fields in the
+ TQSqlRecord \a other.
+*/
+TQSqlRecordInfo::TQSqlRecordInfo( const TQSqlRecord& other )
+{
+ for ( uint i = 0; i < other.count(); ++i ) {
+ push_back( TQSqlFieldInfo( *(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.
+*/
+TQSqlRecordInfo::size_type TQSqlRecordInfo::contains( const TQString& fieldName ) const
+{
+ size_type i = 0;
+ TQString fName = fieldName.upper();
+ for( const_iterator it = begin(); it != end(); ++it ) {
+ if ( (*it).name().upper() == fName ) {
+ ++i;
+ }
+ }
+ return i;
+}
+
+/*!
+ Returns a TQSqlFieldInfo object for the first field in the record
+ which has the field name \a fieldName. If no matching field is
+ found then an empty TQSqlFieldInfo object is returned.
+*/
+TQSqlFieldInfo TQSqlRecordInfo::find( const TQString& fieldName ) const
+{
+ TQString fName = fieldName.upper();
+ for( const_iterator it = begin(); it != end(); ++it ) {
+ if ( (*it).name().upper() == fName ) {
+ return *it;
+ }
+ }
+ return TQSqlFieldInfo();
+}
+
+/*!
+ Returns an empty TQSqlRecord based on the field information
+ in this TQSqlRecordInfo.
+*/
+TQSqlRecord TQSqlRecordInfo::toRecord() const
+{
+ TQSqlRecord buf;
+ for( const_iterator it = begin(); it != end(); ++it ) {
+ buf.append( (*it).toField() );
+ }
+ return buf;
+}
+
+/*!
+ \fn TQSqlRecordInfo::TQSqlRecordInfo()
+
+ Constructs an empty record info object
+*/
+
+/*!
+ \fn TQSqlRecordInfo::TQSqlRecordInfo( const TQSqlFieldInfoList& other )
+
+ Constructs a copy of \a other.
+*/
+
+#endif
diff --git a/src/sql/qsqlrecord.h b/src/sql/qsqlrecord.h
new file mode 100644
index 000000000..9fd499364
--- /dev/null
+++ b/src/sql/qsqlrecord.h
@@ -0,0 +1,141 @@
+/****************************************************************************
+**
+** Definition of TQSqlRecord class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLRECORD_H
+#define TQSQLRECORD_H
+
+#ifndef QT_H
+#include "qstring.h"
+#include "qstringlist.h"
+#include "qvariant.h"
+#include "qsqlfield.h"
+#endif // QT_H
+
+#ifndef QT_NO_SQL
+
+class TQSqlRecordPrivate;
+
+class TQSqlRecordShared : public TQShared
+{
+public:
+ TQSqlRecordShared( TQSqlRecordPrivate* sqlRecordPrivate )
+ : d( sqlRecordPrivate )
+ {}
+ virtual ~TQSqlRecordShared();
+ TQSqlRecordPrivate* d;
+};
+
+class Q_EXPORT TQSqlRecord
+{
+public:
+ TQSqlRecord();
+ TQSqlRecord( const TQSqlRecord& other );
+ TQSqlRecord& operator=( const TQSqlRecord& other );
+ virtual ~TQSqlRecord();
+ virtual TQVariant value( int i ) const;
+ virtual TQVariant value( const TQString& name ) const;
+ virtual void setValue( int i, const TQVariant& val );
+ virtual void setValue( const TQString& name, const TQVariant& val );
+ bool isGenerated( int i ) const;
+ bool isGenerated( const TQString& name ) const;
+ virtual void setGenerated( const TQString& name, bool generated );
+ virtual void setGenerated( int i, bool generated );
+ virtual void setNull( int i );
+ virtual void setNull( const TQString& name );
+ bool isNull( int i ); // remove in 4.0
+ bool isNull( const TQString& name ); // remove in 4.0
+ bool isNull( int i ) const;
+ bool isNull( const TQString& name ) const;
+
+ int position( const TQString& name ) const;
+ TQString fieldName( int i ) const;
+ TQSqlField* field( int i );
+ TQSqlField* field( const TQString& name );
+ const TQSqlField* field( int i ) const;
+ const TQSqlField* field( const TQString& name ) const;
+
+ virtual void append( const TQSqlField& field );
+ virtual void insert( int pos, const TQSqlField& field );
+ virtual void remove( int pos );
+
+ bool isEmpty() const;
+ bool contains( const TQString& name ) const;
+ virtual void clear();
+ virtual void clearValues( bool nullify = FALSE );
+ uint count() const;
+ virtual TQString toString( const TQString& prefix = TQString::null,
+ const TQString& sep = "," ) const;
+ virtual TQStringList toStringList( const TQString& prefix = TQString::null ) const;
+
+private:
+ TQString createField( int i, const TQString& prefix ) const;
+ void deref();
+ bool checkDetach();
+ TQSqlRecordShared* sh;
+};
+
+/******************************************/
+/******* TQSqlRecordInfo Class ******/
+/******************************************/
+
+#if defined(Q_TEMPLATEDLL)
+// MOC_SKIP_BEGIN
+Q_TEMPLATE_EXTERN template class Q_EXPORT TQValueList<TQSqlFieldInfo>;
+// MOC_SKIP_END
+#endif
+
+typedef TQValueList<TQSqlFieldInfo> TQSqlFieldInfoList;
+
+class Q_EXPORT TQSqlRecordInfo: public TQSqlFieldInfoList
+{
+public:
+ TQSqlRecordInfo(): TQSqlFieldInfoList() {}
+ TQSqlRecordInfo( const TQSqlFieldInfoList& other ): TQSqlFieldInfoList( other ) {}
+ TQSqlRecordInfo( const TQSqlRecord& other );
+
+ size_type contains( const TQString& fieldName ) const;
+ TQSqlFieldInfo find( const TQString& fieldName ) const;
+ TQSqlRecord toRecord() const;
+
+};
+
+
+#endif // QT_NO_SQL
+#endif
diff --git a/src/sql/qsqlresult.cpp b/src/sql/qsqlresult.cpp
new file mode 100644
index 000000000..6407064d4
--- /dev/null
+++ b/src/sql/qsqlresult.cpp
@@ -0,0 +1,368 @@
+/****************************************************************************
+**
+** Implementation of TQSqlResult class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlResultPrivate
+{
+public:
+ const TQSqlDriver* sqldriver;
+ int idx;
+ TQString sql;
+ bool active;
+ bool isSel;
+ TQSqlError error;
+ TQSqlExtension * ext;
+};
+
+/*!
+ \class TQSqlResult
+ \brief The TQSqlResult class provides an abstract interface for
+ accessing data from SQL databases.
+
+ \ingroup database
+ \module sql
+
+ Normally you would use TQSqlQuery instead of TQSqlResult since TQSqlQuery
+ provides a generic wrapper for database-specific implementations of
+ TQSqlResult.
+
+ \sa TQSql
+*/
+
+
+/*!
+ Protected constructor which creates a TQSqlResult using database \a
+ db. The object is initialized to an inactive state.
+*/
+
+TQSqlResult::TQSqlResult( const TQSqlDriver * db ): forwardOnly( FALSE )
+{
+ d = new TQSqlResultPrivate();
+ d->sqldriver = db;
+ d->idx = TQSql::BeforeFirst;
+ d->isSel = FALSE;
+ d->active = FALSE;
+ d->ext = new TQSqlExtension();
+}
+
+/*!
+ Destroys the object and frees any allocated resources.
+*/
+
+TQSqlResult::~TQSqlResult()
+{
+ 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 TQSqlResult::setQuery( const TQString& query )
+{
+ d->sql = query;
+}
+
+/*!
+ Returns the current SQL query text, or TQString::null if there is none.
+*/
+
+TQString TQSqlResult::lastQuery() const
+{
+ return d->sql;
+}
+
+/*!
+ Returns the current (zero-based) position of the result.
+*/
+
+int TQSqlResult::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 TQSqlResult::isValid() const
+{
+ return ( d->idx != TQSql::BeforeFirst && \
+ d->idx != TQSql::AfterLast ) ? TRUE : FALSE;
+}
+
+/*!
+ \fn bool TQSqlResult::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 TQSqlResult::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 TQSqlResult::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 TQSqlResult::setSelect( bool s )
+{
+ d->isSel = s;
+}
+
+/*!
+ Returns TRUE if the current result is from a SELECT statement;
+ otherwise returns FALSE.
+*/
+
+bool TQSqlResult::isSelect() const
+{
+ return d->isSel;
+}
+
+/*!
+ Returns the driver associated with the result.
+*/
+
+const TQSqlDriver* TQSqlResult::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 TQSqlResult::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 TQSqlResult::setLastError( const TQSqlError& e )
+{
+ d->error = e;
+}
+
+
+/*!
+ Returns the last error associated with the result.
+*/
+
+TQSqlError TQSqlResult::lastError() const
+{
+ return d->error;
+}
+
+/*!
+ \fn int TQSqlResult::size()
+
+ Returns the size of the result or -1 if it cannot be determined.
+*/
+
+/*!
+ \fn int TQSqlResult::numRowsAffected()
+
+ Returns the number of rows affected by the last query executed.
+*/
+
+/*!
+ \fn TQVariant TQSqlResult::data( int i )
+
+ Returns the data for field \a i (zero-based) as a TQVariant. 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 TQVariant() if it cannot be determined.
+*/
+
+/*!
+ \fn bool TQSqlResult::reset( const TQString& 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 TQSqlResult::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 TQSqlResult::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 TQSqlResult::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 TQSqlResult::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 TQSqlResult::fetchPrev()
+{
+ return fetch( at() - 1 );
+}
+
+/*!
+ Returns TRUE if you can only scroll forward through a result set;
+ otherwise returns FALSE.
+*/
+bool TQSqlResult::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 TQSqlResult::setForwardOnly( bool forward )
+{
+ forwardOnly = forward;
+}
+
+// XXX BCI HACK - remove in 4.0
+/*! \internal */
+void TQSqlResult::setExtension( TQSqlExtension * ext )
+{
+ if ( d->ext )
+ delete d->ext;
+ d->ext = ext;
+}
+
+/*! \internal */
+TQSqlExtension * TQSqlResult::extension()
+{
+ return d->ext;
+}
+#endif // QT_NO_SQL
diff --git a/src/sql/qsqlresult.h b/src/sql/qsqlresult.h
new file mode 100644
index 000000000..52874db56
--- /dev/null
+++ b/src/sql/qsqlresult.h
@@ -0,0 +1,115 @@
+/****************************************************************************
+**
+** Definition of TQSqlResult class
+**
+** Created : 2000-11-03
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLRESULT_H
+#define TQSQLRESULT_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 TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL
+
+class TQSqlDriver;
+class TQSql;
+class TQSqlResultPrivate;
+class TQSqlExtension;
+
+class TQM_EXPORT_SQL TQSqlResult
+{
+friend class TQSqlQuery;
+friend class TQSqlResultShared;
+public:
+ virtual ~TQSqlResult();
+
+ // BCI HACK - remove in 4.0
+ void setExtension( TQSqlExtension * ext );
+ TQSqlExtension * extension();
+
+protected:
+ TQSqlResult(const TQSqlDriver * db );
+ int at() const;
+ TQString lastQuery() const;
+ TQSqlError lastError() const;
+ bool isValid() const;
+ bool isActive() const;
+ bool isSelect() const;
+ bool isForwardOnly() const;
+ const TQSqlDriver* driver() const;
+ virtual void setAt( int at );
+ virtual void setActive( bool a );
+ virtual void setLastError( const TQSqlError& e );
+ virtual void setQuery( const TQString& query );
+ virtual void setSelect( bool s );
+ virtual void setForwardOnly( bool forward );
+
+ virtual TQVariant data( int i ) = 0;
+ virtual bool isNull( int i ) = 0;
+ virtual bool reset ( const TQString& 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:
+ TQSqlResultPrivate* d;
+ bool forwardOnly;
+
+private: // Disabled copy constructor and operator=
+#if defined(Q_DISABLE_COPY)
+ TQSqlResult( const TQSqlResult & );
+ TQSqlResult &operator=( const TQSqlResult & );
+#endif
+};
+
+#endif // QT_NO_SQL
+#endif
diff --git a/src/sql/qsqlselectcursor.cpp b/src/sql/qsqlselectcursor.cpp
new file mode 100644
index 000000000..037a79854
--- /dev/null
+++ b/src/sql/qsqlselectcursor.cpp
@@ -0,0 +1,249 @@
+/****************************************************************************
+**
+** Definition of TQSqlSelectCursor class
+**
+** Created : 2002-11-13
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSqlSelectCursorPrivate
+{
+public:
+ TQSqlSelectCursorPrivate() : populated( FALSE ) {}
+ TQString query;
+ bool populated : 1;
+};
+
+/*!
+ \class TQSqlSelectCursor qsqlselectcursor.h
+ \brief The TQSqlSelectCursor class provides browsing of general SQL
+ SELECT statements.
+
+ \ingroup database
+ \module sql
+
+ TQSqlSelectCursor is a convenience class that makes it possible to
+ display result sets from general SQL \c SELECT statements in
+ data-aware TQt widgets. TQSqlSelectCursor 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
+ TQSqlSelectCursor::exec() function.
+
+ Example:
+ \code
+ ...
+ TQSqlSelectCursor* cur = new TQSqlSelectCursor( "SELECT id, firstname, lastname FROM author" );
+ TQDataTable* table = new TQDataTable( 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.
+ */
+TQSqlSelectCursor::TQSqlSelectCursor( const TQString& query, TQSqlDatabase* db )
+ : TQSqlCursor( TQString::null, FALSE, db )
+{
+ d = new TQSqlSelectCursorPrivate;
+ d->query = query;
+ TQSqlCursor::setMode( ReadOnly );
+ if ( !query.isNull() )
+ exec( query );
+}
+
+/*! Constructs a copy of \a other */
+TQSqlSelectCursor::TQSqlSelectCursor( const TQSqlSelectCursor& other )
+ : TQSqlCursor( other )
+{
+ d = new TQSqlSelectCursorPrivate;
+ d->query = other.d->query;
+ d->populated = other.d->populated;
+}
+
+/*! Destroys the object and frees any allocated resources */
+TQSqlSelectCursor::~TQSqlSelectCursor()
+{
+ delete d;
+}
+
+/*! \reimp */
+bool TQSqlSelectCursor::exec( const TQString& query )
+{
+ d->query = query;
+ bool ret = TQSqlCursor::exec( query );
+ if ( ret ) {
+ TQSqlCursor::clear();
+ populateCursor();
+ }
+ return ret;
+}
+
+/*! \fn bool TQSqlSelectCursor::select()
+ \reimp
+*/
+
+/*! \reimp */
+bool TQSqlSelectCursor::select( const TQString&, const TQSqlIndex& )
+{
+ bool ret = TQSqlCursor::exec( d->query );
+ if ( ret && !d->populated )
+ populateCursor();
+ return ret;
+}
+
+/*! \internal */
+void TQSqlSelectCursor::populateCursor()
+{
+ TQSqlRecordInfo inf = driver()->recordInfo( *(TQSqlQuery*)this );
+ for ( TQSqlRecordInfo::const_iterator it = inf.begin(); it != inf.end(); ++it )
+ TQSqlCursor::append( *it );
+ d->populated = TRUE;
+}
+
+/*! \fn TQSqlIndex TQSqlSelectCursor::primaryIndex( bool ) const
+ \reimp
+*/
+
+/*! \fn TQSqlIndex TQSqlSelectCursor::index( const TQStringList& ) const
+ \reimp
+*/
+
+/*! \fn TQSqlIndex TQSqlSelectCursor::index( const TQString& ) const
+ \reimp
+*/
+
+/*! \fn TQSqlIndex TQSqlSelectCursor::index( const char* ) const
+ \reimp
+*/
+
+/*! \fn void TQSqlSelectCursor::setPrimaryIndex( const TQSqlIndex& )
+ \reimp
+*/
+
+/*! \fn void TQSqlSelectCursor::append( const TQSqlFieldInfo& )
+ \reimp
+*/
+
+/*! \fn void TQSqlSelectCursor::insert( int, const TQSqlFieldInfo& )
+ \reimp
+*/
+
+/*! \fn void TQSqlSelectCursor::remove( int )
+ \reimp
+*/
+
+/*! \fn void TQSqlSelectCursor::clear()
+ \reimp
+*/
+
+/*! \fn void TQSqlSelectCursor::setGenerated( const TQString&, bool )
+ \reimp
+*/
+
+/*! \fn void TQSqlSelectCursor::setGenerated( int, bool )
+ \reimp
+*/
+
+/*! \fn TQSqlRecord* TQSqlSelectCursor::editBuffer( bool )
+ \reimp
+*/
+
+/*! \fn TQSqlRecord* TQSqlSelectCursor::primeInsert()
+ \reimp
+*/
+
+/*! \fn TQSqlRecord* TQSqlSelectCursor::primeUpdate()
+ \reimp
+*/
+
+/*! \fn TQSqlRecord* TQSqlSelectCursor::primeDelete()
+ \reimp
+*/
+
+/*! \fn int TQSqlSelectCursor::insert( bool )
+ \reimp
+*/
+
+/*! \fn int TQSqlSelectCursor::update( bool )
+ \reimp
+*/
+
+/*! \fn int TQSqlSelectCursor::del( bool )
+ \reimp
+*/
+
+/*! \fn void TQSqlSelectCursor::setMode( int )
+ \reimp
+*/
+
+/*! \fn void TQSqlSelectCursor::setSort( const TQSqlIndex& )
+ \reimp
+*/
+
+/*! \fn TQSqlIndex TQSqlSelectCursor::sort() const
+ \reimp
+*/
+
+/*! \fn void TQSqlSelectCursor::setFilter( const TQString& )
+ \reimp
+*/
+
+/*! \fn TQString TQSqlSelectCursor::filter() const
+ \reimp
+*/
+
+/*! \fn void TQSqlSelectCursor::setName( const TQString&, bool )
+ \reimp
+*/
+
+/*! \fn TQString TQSqlSelectCursor::name() const
+ \reimp
+*/
+
+/*! \fn TQString TQSqlSelectCursor::toString( const TQString&, const TQString& ) const
+ \reimp
+*/
+#endif // QT_NO_SQL
diff --git a/src/sql/qsqlselectcursor.h b/src/sql/qsqlselectcursor.h
new file mode 100644
index 000000000..f1c03611f
--- /dev/null
+++ b/src/sql/qsqlselectcursor.h
@@ -0,0 +1,104 @@
+/****************************************************************************
+**
+** Definition of TQSqlSelectCursor class
+**
+** Created : 2002-11-13
+**
+** Copyright (C) 2005-2008 Trolltech ASA. All rights reserved.
+**
+** This file is part of the sql module of the TQt 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 TQt Foundation.
+**
+** Please review the following information to ensure GNU General
+** Public Licensing retquirements 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.TQPL
+** included in the packaging of this file. Licensees holding valid TQt
+** Commercial licenses may use this file in accordance with the TQt
+** 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 TQSQLSELECTCURSOR_H
+#define TQSQLSELECTCURSOR_H
+
+#ifndef QT_H
+#include "qsqlcursor.h"
+#endif // QT_H
+
+#if !defined( QT_MODULE_SQL ) || defined( QT_LICENSE_PROFESSIONAL )
+#define TQM_EXPORT_SQL
+#else
+#define TQM_EXPORT_SQL Q_EXPORT
+#endif
+
+#ifndef QT_NO_SQL
+
+class TQSqlSelectCursorPrivate;
+
+class TQM_EXPORT_SQL TQSqlSelectCursor : public TQSqlCursor
+{
+public:
+ TQSqlSelectCursor( const TQString& query = TQString::null, TQSqlDatabase* db = 0 );
+ TQSqlSelectCursor( const TQSqlSelectCursor& other );
+ ~TQSqlSelectCursor();
+ bool exec( const TQString& query );
+ bool select() { return TQSqlCursor::select(); }
+
+protected:
+ TQSqlIndex primaryIndex( bool = TRUE ) const { return TQSqlIndex(); }
+ TQSqlIndex index( const TQStringList& ) const { return TQSqlIndex(); }
+ TQSqlIndex index( const TQString& ) const { return TQSqlIndex(); }
+ TQSqlIndex index( const char* ) const { return TQSqlIndex(); }
+ void setPrimaryIndex( const TQSqlIndex& ) {}
+ void append( const TQSqlFieldInfo& ) {}
+ void insert( int, const TQSqlFieldInfo& ) {}
+ void remove( int ) {}
+ void clear() {}
+ void setGenerated( const TQString&, bool ) {}
+ void setGenerated( int, bool ) {}
+ TQSqlRecord* editBuffer( bool = FALSE ) { return 0; }
+ TQSqlRecord* primeInsert() { return 0; }
+ TQSqlRecord* primeUpdate() { return 0; }
+ TQSqlRecord* 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 TQSqlIndex& ) {}
+ TQSqlIndex sort() const { return TQSqlIndex(); }
+ void setFilter( const TQString& ) {}
+ TQString filter() const { return TQString::null; }
+ void setName( const TQString&, bool = TRUE ) {}
+ TQString name() const { return TQString::null; }
+ TQString toString( const TQString& = TQString::null, const TQString& = "," ) const { return TQString::null; }
+ bool select( const TQString &, const TQSqlIndex& = TQSqlIndex() );
+
+private:
+ void populateCursor();
+
+ TQSqlSelectCursorPrivate * d;
+};
+
+#endif // QT_NO_SQL
+#endif // TQSQLSELECTCURSOR_H
diff --git a/src/sql/qt_sql.pri b/src/sql/qt_sql.pri
new file mode 100644
index 000000000..5533c6fbe
--- /dev/null
+++ b/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
+ }
+}
+