summaryrefslogtreecommitdiffstats
path: root/tqtinterface/qt4/src/sql/drivers/ibase/tqsql_ibase.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'tqtinterface/qt4/src/sql/drivers/ibase/tqsql_ibase.cpp')
-rw-r--r--tqtinterface/qt4/src/sql/drivers/ibase/tqsql_ibase.cpp1078
1 files changed, 0 insertions, 1078 deletions
diff --git a/tqtinterface/qt4/src/sql/drivers/ibase/tqsql_ibase.cpp b/tqtinterface/qt4/src/sql/drivers/ibase/tqsql_ibase.cpp
deleted file mode 100644
index 735363c..0000000
--- a/tqtinterface/qt4/src/sql/drivers/ibase/tqsql_ibase.cpp
+++ /dev/null
@@ -1,1078 +0,0 @@
-/****************************************************************************
-**
-** Implementation of Interbase driver classes.
-**
-** Copyright (C) 2010 Timothy Pearson and (C) 1992-2008 Trolltech ASA.
-**
-** 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 "tqsql_ibase.h"
-
-#include <tqdatetime.h>
-#include <private/tqsqlextension_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(XSTQLDA *&sqlda)
-{
- sqlda = (XSTQLDA *) malloc(XSTQLDA_LENGTH(1));
- sqlda->sqln = 1;
- sqlda->sqld = 0;
- sqlda->version = STQLDA_VERSION1;
- sqlda->sqlvar[0].sqlind = 0;
- sqlda->sqlvar[0].sqldata = 0;
-}
-
-static void enlargeDA(XSTQLDA *&sqlda, int n)
-{
- free(sqlda);
- sqlda = (XSTQLDA *) malloc(XSTQLDA_LENGTH(n));
- sqlda->sqln = n;
- sqlda->version = STQLDA_VERSION1;
-}
-
-static void initDA(XSTQLDA *sqlda)
-{
- for (int i = 0; i < sqlda->sqld; ++i) {
- switch (sqlda->sqlvar[i].sqltype & ~1) {
- case STQL_INT64:
- case STQL_LONG:
- case STQL_SHORT:
- case STQL_FLOAT:
- case STQL_DOUBLE:
- case STQL_TIMESTAMP:
- case STQL_TYPE_TIME:
- case STQL_TYPE_DATE:
- case STQL_TEXT:
- case STQL_BLOB:
- sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen);
- break;
- case STQL_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(XSTQLDA *&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 STQL_VARYING:
- case STQL_TEXT:
- return TQVariant::String;
- case STQL_LONG:
- case STQL_SHORT:
- return TQVariant::Int;
- case STQL_INT64:
- return TQVariant::LongLong;
- case STQL_FLOAT:
- case STQL_DOUBLE:
- return TQVariant::Double;
- case STQL_TIMESTAMP:
- return TQVariant::DateTime;
- case STQL_TYPE_DATE:
- return TQVariant::Date;
- case STQL_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_TQUAD *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;
- XSTQLDA *sqlda; // output sqlda
- XSTQLDA *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, DSTQL_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_TQUAD *bId = (ISC_TQUAD*)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_TQUAD *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 STQL_INT64:
- if (d->inda->sqlvar[para].sqlscale < 0)
- *((TQ_LLONG*)d->inda->sqlvar[para].sqldata) = TQ_LLONG(val.toDouble() *
- pow(10.0, d->inda->sqlvar[para].sqlscale * -1));
- else
- *((TQ_LLONG*)d->inda->sqlvar[para].sqldata) = val.toLongLong();
- break;
- case STQL_LONG:
- *((long*)d->inda->sqlvar[para].sqldata) = (long)val.toLongLong();
- break;
- case STQL_SHORT:
- *((short*)d->inda->sqlvar[para].sqldata) = (short)val.toInt();
- break;
- case STQL_FLOAT:
- *((float*)d->inda->sqlvar[para].sqldata) = (float)val.toDouble();
- break;
- case STQL_DOUBLE:
- *((double*)d->inda->sqlvar[para].sqldata) = val.toDouble();
- break;
- case STQL_TIMESTAMP:
- *((ISC_TIMESTAMP*)d->inda->sqlvar[para].sqldata) = toTimeStamp(val.toDateTime());
- break;
- case STQL_TYPE_TIME:
- *((ISC_TIME*)d->inda->sqlvar[para].sqldata) = toTime(val.toTime());
- break;
- case STQL_TYPE_DATE:
- *((ISC_DATE*)d->inda->sqlvar[para].sqldata) = toDate(val.toDate());
- break;
- case STQL_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 STQL_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 STQL_BLOB:
- d->writeBlob(para, val.toByteArray());
- break;
- default:
- break;
- }
- }
- }
-
- if (colCount()) {
- isc_dsql_free_statement(d->status, &d->stmt, DSTQL_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 = (XSTQLDA *) malloc(XSTQLDA_LENGTH(n));
- d->sqlda->sqln = n;
- d->sqlda->version = STQLDA_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;
-
- TQ_ASSERT(row);
- TQ_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;
- TQ_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 STQL_VARYING:
- // pascal strings - a short with a length information followed by the data
- (*row)[i] = TQString::fromUtf8(buf + sizeof(short), *(short*)buf);
- break;
- case STQL_INT64:
- if (d->sqlda->sqlvar[i].sqlscale < 0)
- (*row)[i] = *(TQ_LLONG*)buf * pow(10.0, d->sqlda->sqlvar[i].sqlscale);
- else
- (*row)[i] = TQVariant(*(TQ_LLONG*)buf);
- break;
- case STQL_LONG:
- if (sizeof(int) == sizeof(long)) //dear compiler: please optimize me out.
- (*row)[i] = TQVariant((int)(*(long*)buf));
- else
- (*row)[i] = TQVariant((TQ_LLONG)(*(long*)buf));
- break;
- case STQL_SHORT:
- (*row)[i] = TQVariant((int)(*(short*)buf));
- break;
- case STQL_FLOAT:
- (*row)[i] = TQVariant((double)(*(float*)buf));
- break;
- case STQL_DOUBLE:
- (*row)[i] = TQVariant(*(double*)buf);
- break;
- case STQL_TIMESTAMP:
- (*row)[i] = toTQDateTime((ISC_TIMESTAMP*)buf);
- break;
- case STQL_TYPE_TIME:
- (*row)[i] = toTQTime(*(ISC_TIME*)buf);
- break;
- case STQL_TYPE_DATE:
- (*row)[i] = toTQDate(*(ISC_DATE*)buf);
- break;
- case STQL_TEXT:
- (*row)[i] = TQString::fromUtf8(buf, size);
- break;
- case STQL_BLOB:
- (*row)[i] = d->fetchBlob((ISC_TQUAD*)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;
- XSTQLVAR v;
- for (int i = 0; i < result->d->sqlda->sqld; ++i) {
- v = result->d->sqlda->sqlvar[i];
- TQSqlField f(TQString::tqfromLatin1(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;
- XSTQLVAR v;
- for (int i = 0; i < result->d->sqlda->sqld; ++i) {
- v = result->d->sqlda->sqlvar[i];
- TQSqlFieldInfo f(TQString::tqfromLatin1(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);
- }
-}