⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 qsql_ibase.cpp

📁 Trolltech公司发布的基于C++图形开发环境
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/******************************************************************************** Implementation of Interbase driver classes.**** Copyright (C) 1992-2004 Trolltech AS. All rights reserved.**** This file is part of the sql module of the Qt GUI Toolkit.** EDITIONS: FREE, ENTERPRISE**** This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE** WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.******************************************************************************/#include "qsql_ibase.h"#include <qdatetime.h>#include <private/qsqlextension_p.h>#include <ibase.h>#include <stdlib.h>#include <limits.h>#include <math.h>#define QIBASE_DRIVER_NAME "QIBASE"class QIBasePreparedExtension : public QSqlExtension{public:    QIBasePreparedExtension(QIBaseResult *r)	: result(r) {}    bool prepare(const QString &query)    {	return result->prepare(query);    }        bool exec()    {	return result->exec();    }    QIBaseResult *result;};static bool getIBaseError(QString& msg, ISC_STATUS* status, long &sqlcode){    if (status[0] != 1 || status[1] <= 0)	return FALSE;        sqlcode = isc_sqlcode(status);    char buf[512];    isc_sql_interprete(sqlcode, buf, 512);    msg = QString::fromUtf8(buf);    return TRUE;}static void createDA(XSQLDA *&sqlda){    sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(1));    sqlda->sqln = 1;    sqlda->sqld = 0;    sqlda->version = SQLDA_VERSION1;    sqlda->sqlvar[0].sqlind = 0;    sqlda->sqlvar[0].sqldata = 0;}static void enlargeDA(XSQLDA *&sqlda, int n){    free(sqlda);    sqlda = (XSQLDA *) malloc(XSQLDA_LENGTH(n));    sqlda->sqln = n;    sqlda->version = SQLDA_VERSION1;    }static void initDA(XSQLDA *sqlda){    for (int i = 0; i < sqlda->sqld; ++i) {	switch (sqlda->sqlvar[i].sqltype & ~1) {	case SQL_INT64:	case SQL_LONG:	case SQL_SHORT:	case SQL_FLOAT:	case SQL_DOUBLE:	case SQL_TIMESTAMP:	case SQL_TYPE_TIME:        case SQL_TYPE_DATE:	case SQL_TEXT:	case SQL_BLOB:	    sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen);	    break;	case SQL_VARYING:	    sqlda->sqlvar[i].sqldata = (char*)malloc(sqlda->sqlvar[i].sqllen + sizeof(short));	    break;	default:	    // not supported - do not bind.	    sqlda->sqlvar[i].sqldata = 0;	    break;	}	if (sqlda->sqlvar[i].sqltype & 1) {	    sqlda->sqlvar[i].sqlind = (short*)malloc(sizeof(short));	    *(sqlda->sqlvar[i].sqlind) = 0;	} else {	    sqlda->sqlvar[i].sqlind = 0;	}    }}static void delDA(XSQLDA *&sqlda){    if (!sqlda)	return;    for (int i = 0; i < sqlda->sqld; ++i) {	free(sqlda->sqlvar[i].sqlind);	free(sqlda->sqlvar[i].sqldata);    }    free(sqlda);    sqlda = 0;    }static QVariant::Type qIBaseTypeName(int iType){    switch (iType) {    case blr_varying:    case blr_varying2:    case blr_text:    case blr_cstring:    case blr_cstring2:	return QVariant::String;    case blr_sql_time:	return QVariant::Time;    case blr_sql_date:        return QVariant::Date;    case blr_timestamp:	return QVariant::DateTime;    case blr_blob:	return QVariant::ByteArray;    case blr_quad:    case blr_short:    case blr_long:	return QVariant::Int;    case blr_int64:	return QVariant::LongLong;    case blr_float:    case blr_d_float:    case blr_double:	return QVariant::Double;    }    return QVariant::Invalid;}static QVariant::Type qIBaseTypeName2(int iType){    switch(iType & ~1) {    case SQL_VARYING:    case SQL_TEXT:	return QVariant::String;    case SQL_LONG:    case SQL_SHORT:	return QVariant::Int;    case SQL_INT64:	return QVariant::LongLong;    case SQL_FLOAT:    case SQL_DOUBLE:	return QVariant::Double;    case SQL_TIMESTAMP:	return QVariant::DateTime;    case SQL_TYPE_DATE:        return QVariant::Date;    case SQL_TYPE_TIME:	return QVariant::Time;    default:	return QVariant::Invalid;    }}static ISC_TIME toTime(const QTime &t){    static const QTime midnight(0, 0, 0, 0);    return (ISC_TIME)midnight.msecsTo(t) * 10;}static ISC_DATE toDate(const QDate &d){    static const QDate basedate(1858, 11, 17);    return (ISC_DATE)basedate.daysTo(d);}static ISC_TIMESTAMP toTimeStamp(const QDateTime &dt){    ISC_TIMESTAMP ts;    ts.timestamp_time = toTime(dt.time());    ts.timestamp_date = toDate(dt.date());    return ts;}static QTime toQTime(ISC_TIME time){    // have to demangle the structure ourselves because isc_decode_time    // strips the msecs    static const QTime t;    return t.addMSecs(time / 10);}static QDate toQDate(ISC_DATE d){    static const QDate bd(1858, 11, 17);    return bd.addDays(d);}static QDateTime toQDateTime(ISC_TIMESTAMP *ts){    return QDateTime(toQDate(ts->timestamp_date), toQTime(ts->timestamp_time));}class QIBaseDriverPrivate{public:    QIBaseDriverPrivate(QIBaseDriver *d): q(d)    {	ibase = 0;	trans = 0;    }        bool isError(const QString &msg = QString::null, QSqlError::Type typ = QSqlError::Unknown)     {	QString imsg;	long sqlcode;	if (!getIBaseError(imsg, status, sqlcode))	    return FALSE;		q->setLastError(QSqlError(msg, imsg, typ, (int)sqlcode));	return TRUE;    }public:        QIBaseDriver* q;    isc_db_handle ibase;    isc_tr_handle trans;    ISC_STATUS status[20];    };class QIBaseResultPrivate{public:    QIBaseResultPrivate(QIBaseResult *d, const QIBaseDriver *ddb);    ~QIBaseResultPrivate() { cleanup(); }        void cleanup();    bool isError(const QString &msg = QString::null, QSqlError::Type typ = QSqlError::Unknown)     {	QString imsg;	long sqlcode;	if (!getIBaseError(imsg, status, sqlcode))	    return FALSE;		q->setLastError(QSqlError(msg, imsg, typ, (int)sqlcode));	return TRUE;    }            bool transaction();    bool commit();    bool isSelect();    QVariant fetchBlob(ISC_QUAD *bId);    void writeBlob(int i, const QByteArray &ba);public:        QIBaseResult *q;     const QIBaseDriver *db;    ISC_STATUS status[20];    isc_tr_handle trans;    //indicator whether we have a local transaction or a transaction on driver level        bool localTransaction;    isc_stmt_handle stmt;    isc_db_handle ibase;    XSQLDA *sqlda; // output sqlda    XSQLDA *inda; // input parameters    int queryType;};QIBaseResultPrivate::QIBaseResultPrivate(QIBaseResult *d, const QIBaseDriver *ddb):    q(d), db(ddb), trans(0), stmt(0), ibase(ddb->d->ibase), sqlda(0), inda(0), queryType(-1){    localTransaction = (ddb->d->ibase == 0);}void QIBaseResultPrivate::cleanup(){    if (stmt) {	isc_dsql_free_statement(status, &stmt, DSQL_drop);	stmt = 0;    }    commit();    if (!localTransaction)	trans = 0;    delDA(sqlda);    delDA(inda);    queryType = -1;    q->cleanup();}void QIBaseResultPrivate::writeBlob(int i, const QByteArray &ba){    isc_blob_handle handle = 0;    ISC_QUAD *bId = (ISC_QUAD*)inda->sqlvar[i].sqldata;    isc_create_blob2(status, &ibase, &trans, &handle, bId, 0, 0);    if (!isError("Unable to create BLOB", QSqlError::Statement)) {	uint i = 0;	while (i < ba.size()) {	    isc_put_segment(status, &handle, QMIN(ba.size() - i, SHRT_MAX), ba.data());	    if (isError("Unable to write BLOB"))		break;	    i += SHRT_MAX;	}    }    isc_close_blob(status, &handle);}QVariant QIBaseResultPrivate::fetchBlob(ISC_QUAD *bId){    isc_blob_handle handle = 0;    isc_open_blob2(status, &ibase, &trans, &handle, bId, 0, 0);    if (isError("Unable to open BLOB", QSqlError::Statement))	return QVariant();    unsigned short len = 0;    QByteArray ba(255);    ISC_STATUS stat = isc_get_segment(status, &handle, &len, ba.size(), ba.data());    while (status[1] == isc_segment) {	uint osize = ba.size();	// double the amount of data fetched on each iteration	ba.resize(QMIN(ba.size() * 2, SHRT_MAX));	stat = isc_get_segment(status, &handle, &len, osize, ba.data() + osize);    }    bool isErr = isError("Unable to read BLOB", QSqlError::Statement);    isc_close_blob(status, &handle);    if (isErr)	return QVariant();    if (ba.size() > 255)	ba.resize(ba.size() / 2 + len);    else	ba.resize(len);    return ba;}bool QIBaseResultPrivate::isSelect(){    char acBuffer[9];    char qType = isc_info_sql_stmt_type;    isc_dsql_sql_info(status, &stmt, 1, &qType, sizeof(acBuffer), acBuffer);    if (isError("Could not get query info", QSqlError::Statement))	return FALSE;        int iLength = isc_vax_integer(&acBuffer[1], 2);    queryType = isc_vax_integer(&acBuffer[3], iLength);    return (queryType == isc_info_sql_stmt_select);}bool QIBaseResultPrivate::transaction(){    if (trans)	return TRUE;    if (db->d->trans) {	localTransaction = FALSE;	trans = db->d->trans;	return TRUE;    }    localTransaction = TRUE;        isc_start_transaction(status, &trans, 1, &ibase, 0, NULL);    if (isError("Could not start transaction", QSqlError::Statement))	return FALSE;        return TRUE;}// does nothing if the transaction is on the// driver levelbool QIBaseResultPrivate::commit(){    if (!trans)	return FALSE;    // don't commit driver's transaction, the driver will do it for us    if (!localTransaction)	return TRUE;        isc_commit_transaction(status, &trans);    trans = 0;    return !isError("Unable to commit transaction", QSqlError::Statement);}//////////QIBaseResult::QIBaseResult(const QIBaseDriver* db):    QtSqlCachedResult(db){    d = new QIBaseResultPrivate(this, db);    setExtension(new QIBasePreparedExtension(this));}QIBaseResult::~QIBaseResult(){    delete d;}bool QIBaseResult::prepare(const QString& query){    //qDebug("prepare: %s", query.ascii());    if (!driver() || !driver()->isOpen() || driver()->isOpenError())	return FALSE;    d->cleanup();    setActive(FALSE);    setAt(QSql::BeforeFirst);        createDA(d->sqlda);    createDA(d->inda);        if (!d->transaction())	return FALSE;        isc_dsql_allocate_statement(d->status, &d->ibase, &d->stmt);    if (d->isError("Could not allocate statement", QSqlError::Statement))	return FALSE;    isc_dsql_prepare(d->status, &d->trans, &d->stmt, 0, query.utf8().data(), 3, d->sqlda);    if (d->isError("Could not prepare statement", QSqlError::Statement))	return FALSE;        isc_dsql_describe_bind(d->status, &d->stmt, 1, d->inda);    if (d->isError("Could not describe input statement", QSqlError::Statement))	return FALSE;    if (d->inda->sqld > d->inda->sqln) {	enlargeDA(d->inda, d->inda->sqld);	isc_dsql_describe_bind(d->status, &d->stmt, 1, d->inda);	if (d->isError("Could not describe input statement", QSqlError::Statement))	    return FALSE;    }    initDA(d->inda);        if (d->sqlda->sqld > d->sqlda->sqln) {	// need more field descriptors	enlargeDA(d->sqlda, d->sqlda->sqld);	isc_dsql_describe(d->status, &d->stmt, 1, d->sqlda);	if (d->isError("Could not describe statement", QSqlError::Statement))	    return FALSE;    }    initDA(d->sqlda);     setSelect(d->isSelect());    if (!isSelect()) {	free(d->sqlda);	d->sqlda = 0;    }    return TRUE;}bool QIBaseResult::exec(){        if (!driver() || !driver()->isOpen() || driver()->isOpenError())	return FALSE;    setActive(FALSE);    setAt(QSql::BeforeFirst);    if (d->inda && extension()->index.count() > 0) {	QMap<int, QString>::ConstIterator it;	if ((int)extension()->index.count() > d->inda->sqld) {	    qWarning("QIBaseResult::exec: Parameter mismatch, expected %d, got %d parameters", d->inda->sqld, extension()->index.count());	    return FALSE;	}	int para = 0;	for (it = extension()->index.constBegin(); it != extension()->index.constEnd(); ++it, ++para) {	    if (para >= d->inda->sqld)		break;	    if (!d->inda->sqlvar[para].sqldata)		continue;	    const QVariant val(extension()->values[it.data()].value);	    if (d->inda->sqlvar[para].sqltype & 1) {		if (val.isNull()) {		    // set null indicator		    *(d->inda->sqlvar[para].sqlind) = 1;		    // and set the value to 0, otherwise it would count as empty string.		    *((short*)d->inda->sqlvar[para].sqldata) = 0;		    continue;		}		// a value of 0 means non-null.		*(d->inda->sqlvar[para].sqlind) = 0;	    }	    switch(d->inda->sqlvar[para].sqltype & ~1) {	    case SQL_INT64:		if (d->inda->sqlvar[para].sqlscale < 0)		    *((Q_LLONG*)d->inda->sqlvar[para].sqldata) = Q_LLONG(val.toDouble() * 									 pow(10, d->inda->sqlvar[para].sqlscale * -1));		else		    *((Q_LLONG*)d->inda->sqlvar[para].sqldata) = val.toLongLong();		break;	    case SQL_LONG:		*((long*)d->inda->sqlvar[para].sqldata) = (long)val.toLongLong();		break;	    case SQL_SHORT:		*((short*)d->inda->sqlvar[para].sqldata) = (short)val.toInt();		break;	    case SQL_FLOAT:		*((float*)d->inda->sqlvar[para].sqldata) = (float)val.toDouble();		break;	    case SQL_DOUBLE:		*((double*)d->inda->sqlvar[para].sqldata) = val.toDouble();		break;	    case SQL_TIMESTAMP:		*((ISC_TIMESTAMP*)d->inda->sqlvar[para].sqldata) = toTimeStamp(val.toDateTime());		break;	    case SQL_TYPE_TIME:		*((ISC_TIME*)d->inda->sqlvar[para].sqldata) = toTime(val.toTime());		break;            case SQL_TYPE_DATE:		*((ISC_DATE*)d->inda->sqlvar[para].sqldata) = toDate(val.toDate());		break;	    case SQL_VARYING: {		QCString str(val.toString().utf8()); // keep a copy of the string alive in this scope		short buflen = d->inda->sqlvar[para].sqllen;		if (str.length() < (uint)buflen)		    buflen = str.length();		*(short*)d->inda->sqlvar[para].sqldata = buflen; // first two bytes is the length		memcpy(d->inda->sqlvar[para].sqldata + sizeof(short), str.data(), buflen);		break; }	    case SQL_TEXT: {		QCString str(val.toString().utf8().leftJustify(d->inda->sqlvar[para].sqllen, ' ', TRUE));		memcpy(d->inda->sqlvar[para].sqldata, str.data(), d->inda->sqlvar[para].sqllen);		break; }	case SQL_BLOB:		d->writeBlob(para, val.toByteArray());		break;	    default:		break;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -