?? qsql_ibase.cpp
字號(hào):
/******************************************************************************** Copyright (C) 1992-2006 Trolltech ASA. All rights reserved.**** This file is part of the QtSql module of the Qt Toolkit.**** This file may be used under the terms of the GNU General Public** License version 2.0 as published by the Free Software Foundation** and appearing in the file LICENSE.GPL included in the packaging of** this file. Please review the following information to ensure GNU** General Public Licensing requirements will be met:** http://www.trolltech.com/products/qt/opensource.html**** If you are unsure which license is appropriate for your use, please** review the following information:** http://www.trolltech.com/products/qt/licensing.html or contact the** sales department at sales@trolltech.com.**** 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 <qcoreapplication.h>#include <qdatetime.h>#include <qvariant.h>#include <qsqlerror.h>#include <qsqlfield.h>#include <qsqlindex.h>#include <qsqlquery.h>#include <qstringlist.h>#include <qlist.h>#include <qvector.h>#include <qdebug.h>#include <ibase.h>#include <stdlib.h>#include <limits.h>#include <math.h>#define FBVERSION SQL_DIALECT_V6enum { QIBaseChunkSize = SHRT_MAX / 2 };static bool getIBaseError(QString& msg, ISC_STATUS* status, long &sqlcode){ if (status[0] != 1 || status[1] <= 0) return false; sqlcode = isc_sqlcode(status); char buf[512]; isc_sql_interprete(sqlcode, buf, 512); msg = QString::fromUtf8(buf); return true;}static void createDA(XSQLDA *&sqlda){ sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(1)); sqlda->sqln = 1; sqlda->sqld = 0; sqlda->version = SQLDA_VERSION1; sqlda->sqlvar[0].sqlind = 0; sqlda->sqlvar[0].sqldata = 0;}static void enlargeDA(XSQLDA *&sqlda, int n){ free(sqlda); sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(n)); sqlda->sqln = n; sqlda->version = SQLDA_VERSION1;}static void initDA(XSQLDA *sqlda){ for (int i = 0; i < sqlda->sqld; ++i) { switch (sqlda->sqlvar[i].sqltype & ~1) { case SQL_INT64: case SQL_LONG: case SQL_SHORT: case SQL_FLOAT: case SQL_DOUBLE: case SQL_TIMESTAMP: case SQL_TYPE_TIME: case SQL_TYPE_DATE: case SQL_TEXT: case SQL_BLOB: sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen); break; case SQL_ARRAY: sqlda->sqlvar[i].sqldata = (char*)malloc(sizeof(ISC_QUAD)); memset(sqlda->sqlvar[i].sqldata, 0, sizeof(ISC_QUAD)); break; case SQL_VARYING: sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen + sizeof(short)); break; default: // not supported - do not bind. sqlda->sqlvar[i].sqldata = 0; break; } if (sqlda->sqlvar[i].sqltype & 1) { sqlda->sqlvar[i].sqlind = (short*)malloc(sizeof(short)); *(sqlda->sqlvar[i].sqlind) = 0; } else { sqlda->sqlvar[i].sqlind = 0; } }}static void delDA(XSQLDA *&sqlda){ if (!sqlda) return; for (int i = 0; i < sqlda->sqld; ++i) { free(sqlda->sqlvar[i].sqlind); free(sqlda->sqlvar[i].sqldata); } free(sqlda); sqlda = 0;}static QVariant::Type qIBaseTypeName(int iType){ switch (iType) { case blr_varying: case blr_varying2: case blr_text: case blr_cstring: case blr_cstring2: return QVariant::String; case blr_sql_time: return QVariant::Time; case blr_sql_date: return QVariant::Date; case blr_timestamp: return QVariant::DateTime; case blr_blob: return QVariant::ByteArray; case blr_quad: case blr_short: case blr_long: return QVariant::Int; case blr_int64: return QVariant::LongLong; case blr_float: case blr_d_float: case blr_double: return QVariant::Double; } qWarning("qIBaseTypeName: unknown datatype: %d", iType); return QVariant::Invalid;}static QVariant::Type qIBaseTypeName2(int iType){ switch(iType & ~1) { case SQL_VARYING: case SQL_TEXT: return QVariant::String; case SQL_LONG: case SQL_SHORT: return QVariant::Int; case SQL_INT64: return QVariant::LongLong; case SQL_FLOAT: case SQL_DOUBLE: return QVariant::Double; case SQL_TIMESTAMP: return QVariant::DateTime; case SQL_TYPE_TIME: return QVariant::Time; case SQL_TYPE_DATE: return QVariant::Date; case SQL_ARRAY: return QVariant::List; case SQL_BLOB: return QVariant::ByteArray; default: return QVariant::Invalid; }}static ISC_TIMESTAMP toTimeStamp(const QDateTime &dt){ static const QTime midnight(0, 0, 0, 0); static const QDate basedate(1858, 11, 17); ISC_TIMESTAMP ts; ts.timestamp_time = midnight.msecsTo(dt.time()) * 10; ts.timestamp_date = basedate.daysTo(dt.date()); return ts;}static QDateTime fromTimeStamp(char *buffer){ static const QDate bd(1858, 11, 17); QTime t; QDate d; // have to demangle the structure ourselves because isc_decode_time // strips the msecs t = t.addMSecs(int(((ISC_TIMESTAMP*)buffer)->timestamp_time / 10)); d = bd.addDays(int(((ISC_TIMESTAMP*)buffer)->timestamp_date)); return QDateTime(d, t);}static ISC_TIME toTime(const QTime &t){ static const QTime midnight(0, 0, 0, 0); return (ISC_TIME)midnight.msecsTo(t) * 10;}static QTime fromTime(char *buffer){ QTime t; // have to demangle the structure ourselves because isc_decode_time // strips the msecs t = t.addMSecs(int((*(ISC_TIME*)buffer) / 10)); return t;}static ISC_DATE toDate(const QDate &t){ static const QDate basedate(1858, 11, 17); ISC_DATE date; date = basedate.daysTo(t); return date;}static QDate fromDate(char *buffer){ static const QDate bd(1858, 11, 17); QDate d; // have to demangle the structure ourselves because isc_decode_time // strips the msecs d = bd.addDays(int(((ISC_TIMESTAMP*)buffer)->timestamp_date)); return d;}class QIBaseDriverPrivate{public: QIBaseDriverPrivate(QIBaseDriver *d) : q(d) { ibase = 0; trans = 0; } bool isError(const char *msg, QSqlError::ErrorType typ = QSqlError::UnknownError) { QString imsg; long sqlcode; if (!getIBaseError(imsg, status, sqlcode)) return false; //qDebug() << "ERROR" << msg << imsg << typ; q->setLastError(QSqlError(QCoreApplication::translate("QIBaseDriver", msg), imsg, typ, int(sqlcode))); return true; }public: QIBaseDriver* q; isc_db_handle ibase; isc_tr_handle trans; ISC_STATUS status[20];};class QIBaseResultPrivate{public: QIBaseResultPrivate(QIBaseResult *d, const QIBaseDriver *ddb); ~QIBaseResultPrivate() { cleanup(); } void cleanup(); bool isError(const char *msg, QSqlError::ErrorType typ = QSqlError::UnknownError) { QString imsg; long sqlcode; if (!getIBaseError(imsg, status, sqlcode)) return false; q->setLastError(QSqlError(QCoreApplication::translate("QIBaseResult", msg), imsg, typ, int(sqlcode))); return true; } bool transaction(); bool commit(); bool isSelect(); QVariant fetchBlob(ISC_QUAD *bId); bool writeBlob(int i, const QByteArray &ba); QVariant fetchArray(int pos, ISC_QUAD *arr); bool writeArray(int i, const QList<QVariant> &list);public: QIBaseResult *q; const QIBaseDriver *db; ISC_STATUS status[20]; isc_tr_handle trans; //indicator whether we have a local transaction or a transaction on driver level bool localTransaction; isc_stmt_handle stmt; isc_db_handle ibase; XSQLDA *sqlda; // output sqlda XSQLDA *inda; // input parameters int queryType;};QIBaseResultPrivate::QIBaseResultPrivate(QIBaseResult *d, const QIBaseDriver *ddb): q(d), db(ddb), trans(0), stmt(0), ibase(ddb->d->ibase), sqlda(0), inda(0), queryType(-1){ localTransaction = (ddb->d->ibase == 0);}void QIBaseResultPrivate::cleanup(){ commit(); if (!localTransaction) trans = 0; if (stmt) { isc_dsql_free_statement(status, &stmt, DSQL_drop); stmt = 0; } delDA(sqlda); delDA(inda); queryType = -1; q->cleanup();}bool QIBaseResultPrivate::writeBlob(int i, const QByteArray &ba){ isc_blob_handle handle = 0; ISC_QUAD *bId = (ISC_QUAD*)inda->sqlvar[i].sqldata; isc_create_blob2(status, &ibase, &trans, &handle, bId, 0, 0); if (!isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to create BLOB"), QSqlError::StatementError)) { int i = 0; while (i < ba.size()) { isc_put_segment(status, &handle, qMin(ba.size() - i, int(QIBaseChunkSize)), const_cast<char*>(ba.data()) + i); if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to write BLOB"))) return false; i += qMin(ba.size() - i, int(QIBaseChunkSize)); } } isc_close_blob(status, &handle); return true;}QVariant QIBaseResultPrivate::fetchBlob(ISC_QUAD *bId){ isc_blob_handle handle = 0; isc_open_blob2(status, &ibase, &trans, &handle, bId, 0, 0); if (isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to open BLOB"), QSqlError::StatementError)) return QVariant(); unsigned short len = 0; QByteArray ba; int chunkSize = QIBaseChunkSize; ba.resize(chunkSize); int read = 0; while ( isc_get_segment(status, &handle, &len, chunkSize, ba.data() + read) == 0 || status[1] == isc_segment ){ read += len; if ( len < chunkSize ) break; ba.resize(ba.size() + chunkSize); } bool isErr = isError(QT_TRANSLATE_NOOP("QIBaseResult", "Unable to read BLOB"), QSqlError::StatementError); isc_close_blob(status, &handle); if (isErr) return QVariant(); ba.resize(read); return ba;}template<typename T>static QList<QVariant> toList(char** buf, int count, T* = 0){ QList<QVariant> res; for (int i = 0; i < count; ++i) { res.append(*(T*)(*buf)); *buf += sizeof(T); } return res;}/* char** ? seems like bad influence from oracle ... */template<>static QList<QVariant> toList<long>(char** buf, int count, long*){ QList<QVariant> res; for (int i = 0; i < count; ++i) { if (sizeof(int) == sizeof(long)) res.append(int((*(long*)(*buf)))); else res.append((qint64)(*(long*)(*buf))); *buf += sizeof(long); } return res;}static char* readArrayBuffer(QList<QVariant>& list, char *buffer, short curDim, short* numElements, ISC_ARRAY_DESC *arrayDesc){ const short dim = arrayDesc->array_desc_dimensions - 1; const unsigned char dataType = arrayDesc->array_desc_dtype; QList<QVariant> valList; unsigned short strLen = arrayDesc->array_desc_length; if (curDim != dim) { for(int i = 0; i < numElements[curDim]; ++i) buffer = readArrayBuffer(list, buffer, curDim + 1, numElements, arrayDesc); } else { switch(dataType) { case blr_varying: case blr_varying2: strLen += 2; // for the two terminating null values case blr_text: case blr_text2: { int o; for(int i = 0; i < numElements[dim]; ++i) { for(o = 0; o < strLen && buffer[o]!=0; ++o ); valList.append(QString::fromUtf8(buffer, o)); buffer += strLen; } break; } case blr_long: valList = toList<long>(&buffer, numElements[dim], static_cast<long *>(0)); break; case blr_short: valList = toList<short>(&buffer, numElements[dim]); break; case blr_int64: valList = toList<qint64>(&buffer, numElements[dim]); break; case blr_float: valList = toList<float>(&buffer, numElements[dim]); break; case blr_double: valList = toList<double>(&buffer, numElements[dim]); break; case blr_timestamp: for(int i = 0; i < numElements[dim]; ++i) { valList.append(fromTimeStamp(buffer)); buffer += sizeof(ISC_TIMESTAMP); } break; case blr_sql_time: for(int i = 0; i < numElements[dim]; ++i) { valList.append(fromTime(buffer)); buffer += sizeof(ISC_TIME); } break; case blr_sql_date: for(int i = 0; i < numElements[dim]; ++i) { valList.append(fromDate(buffer)); buffer += sizeof(ISC_DATE); } break; } } if (dim > 0) list.append(valList); else list += valList;
?? 快捷鍵說(shuō)明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號(hào)
Ctrl + =
減小字號(hào)
Ctrl + -