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

📄 qsql_sqlite3.cpp

📁 LINUX 下以 QT/KDE 写的 SVN 客户端
💻 CPP
字号:
/******************************************************************************** Implementation of SQLite driver classes.**** Copyright (C) 1992-2003 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_sqlite3.h"#include <qdatetime.h>#include <qvaluevector.h>#include <qregexp.h>#include <qfile.h>#include <sqlite3.h>#if (QT_VERSION-0 < 0x030200)#  include <qvector.h>#  if !defined Q_WS_WIN32#    include <unistd.h>#  endif#else#  include <qptrvector.h>#  if !defined Q_WS_WIN32#    include <unistd.h>#  endif#endiftypedef struct sqlite3_stmt sqlite3_stmt;#define QSQLITE3_DRIVER_NAME "QSQLITE3"static QVariant::Type qSqliteType(int tp){    switch (tp) {    case SQLITE_INTEGER:        return QVariant::Int;    case SQLITE_FLOAT:        return QVariant::Double;    case SQLITE_BLOB:        return QVariant::ByteArray;    case SQLITE_TEXT:    default:        return QVariant::String;    }}static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::Type type,                            int errorCode = -1){    return QSqlError(descr,                     QString::fromUtf8(sqlite3_errmsg(access)),                     type, errorCode);}class QSQLite3DriverPrivate{public:    QSQLite3DriverPrivate();    sqlite3 *access;    bool utf8;};QSQLite3DriverPrivate::QSQLite3DriverPrivate() : access(0){    utf8 = true;}class QSQLite3ResultPrivate{public:    QSQLite3ResultPrivate(QSQLite3Result *res);    void cleanup();    bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch);    bool isSelect();    // initializes the recordInfo and the cache    void initColumns();    void finalize();    QSQLite3Result* q;    sqlite3 *access;    sqlite3_stmt *stmt;    uint skippedStatus: 1; // the status of the fetchNext() that's skipped    uint skipRow: 1; // skip the next fetchNext()?    uint utf8: 1;    QSqlRecord rInf;};static const uint initial_cache_size = 128;QSQLite3ResultPrivate::QSQLite3ResultPrivate(QSQLite3Result* res) : q(res), access(0),    stmt(0), skippedStatus(false), skipRow(false), utf8(false){}void QSQLite3ResultPrivate::cleanup(){    finalize();    rInf.clear();    skippedStatus = false;    skipRow = false;    q->setAt(QSql::BeforeFirst);    q->setActive(false);    q->cleanup();}void QSQLite3ResultPrivate::finalize(){    if (!stmt)        return;    sqlite3_finalize(stmt);    stmt = 0;}// called on first fetchvoid QSQLite3ResultPrivate::initColumns(){    rInf.clear();    int nCols = sqlite3_column_count(stmt);    if (nCols <= 0)        return;    q->init(nCols);    for (int i = 0; i < nCols; ++i) {        QString colName = QString::fromUtf8(sqlite3_column_name(stmt, i));        int dotIdx = colName.findRev('.');        rInf.append(QSqlField(colName.mid(dotIdx == -1 ? 0 : dotIdx + 1),                qSqliteType(sqlite3_column_type(stmt, i))));    }}bool QSQLite3ResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch){    int res;    unsigned int i;    if (skipRow) {        // already fetched        Q_ASSERT(!initialFetch);        skipRow = false;        return skippedStatus;    }    skipRow = initialFetch;    if (!stmt)        return false;    // keep trying while busy, wish I could implement this better.    while ((res = sqlite3_step(stmt)) == SQLITE_BUSY) {        // sleep instead requesting result again immidiately.#if defined Q_OS_WIN        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.            initColumns();        if (idx < 0 && !initialFetch)            return true;        for (i = 0; i < rInf.count(); ++i)            // todo - handle other types            values[i + idx] = QString::fromUtf8((char *)(sqlite3_column_text(stmt, i))); //           values[i + idx] = utf8 ? QString::fromUtf8(fvals[i]) : QString::fromAscii(fvals[i]);        return true;    case SQLITE_DONE:        if (rInf.isEmpty())            // must be first call.            initColumns();        q->setAt(QSql::AfterLast);        return false;    case SQLITE_ERROR:    case SQLITE_MISUSE:    default:        // something wrong, don't get col info, but still return false        q->setLastError(qMakeError(access, "Unable to fetch row", QSqlError::Connection, res));        finalize();        q->setAt(QSql::AfterLast);        return false;    }    return false;}QSQLite3Result::QSQLite3Result(const QSQLite3Driver* db)    : QSqlCachedResult(db){    d = new QSQLite3ResultPrivate(this);    d->access = db->d->access;}QSQLite3Result::~QSQLite3Result(){    d->cleanup();    delete d;}/*   Execute \a query.*/bool QSQLite3Result::reset (const QString &query){    // this is where we build a query.    if (!driver() || !driver()->isOpen() || driver()->isOpenError())        return false;    d->cleanup();    setSelect(false);    int res = sqlite3_prepare_v2(d->access, query.utf8().data(), (query.length() + 1) * sizeof(QChar),                                &d->stmt, 0);    if (res != SQLITE_OK) {        setLastError(qMakeError(d->access, "Unable to execute statement", QSqlError::Statement, res));        d->finalize();        return false;    }    d->skippedStatus = d->fetchNext(cache(), 0, true);    setSelect(!d->rInf.isEmpty());    setActive(true);    return true;}bool QSQLite3Result::gotoNext(QSqlCachedResult::ValueCache& row, int idx){    return d->fetchNext(row, idx, false);}int QSQLite3Result::size(){    return -1;}int QSQLite3Result::numRowsAffected(){    return sqlite3_changes(d->access);}/////////////////////////////////////////////////////////QSQLite3Driver::QSQLite3Driver(QObject * parent, const char *name)    : QSqlDriver(parent, name){    d = new QSQLite3DriverPrivate();}QSQLite3Driver::QSQLite3Driver(sqlite3 *connection, QObject *parent, const char *name)    : QSqlDriver(parent, name){    d = new QSQLite3DriverPrivate();    d->access = connection;    setOpen(true);    setOpenError(false);}QSQLite3Driver::~QSQLite3Driver(){    delete d;}bool QSQLite3Driver::hasFeature(DriverFeature f) const{    switch (f) {    case Transactions:    case Unicode:    case BLOB:        return true;    default:        break;    }    return false;}/*   SQLite dbs have no user name, passwords, hosts or ports.   just file names.*/bool QSQLite3Driver::open(const QString & db, const QString &, const QString &, const QString &, int, const QString &){    if (isOpen())        close();    if (db.isEmpty())        return false;    if (sqlite3_open(QFile::encodeName(db), &d->access) == SQLITE_OK) {        setOpen(true);        setOpenError(false);        return true;    } else {        setLastError(qMakeError(d->access, "Error opening database",                     QSqlError::Connection));        setOpenError(true);        return false;    }}void QSQLite3Driver::close(){    if (isOpen()) {        if (sqlite3_close(d->access) != SQLITE_OK)            setLastError(qMakeError(d->access, "Error closing database",                                    QSqlError::Connection));        d->access = 0;        setOpen(false);        setOpenError(false);    }}QSqlQuery QSQLite3Driver::createQuery() const{    return QSqlQuery(new QSQLite3Result(this));}bool QSQLite3Driver::beginTransaction(){    if (!isOpen() || isOpenError())        return false;    QSqlQuery q(createQuery());    if (!q.exec("BEGIN")) {        setLastError(QSqlError("Unable to begin transaction",                               q.lastError().databaseText(), QSqlError::Transaction));        return false;    }    return true;}bool QSQLite3Driver::commitTransaction(){    if (!isOpen() || isOpenError())        return false;    QSqlQuery q(createQuery());    if (!q.exec("COMMIT")) {        setLastError(QSqlError("Unable to begin transaction",                               q.lastError().databaseText(), QSqlError::Transaction));        return false;    }    return true;}bool QSQLite3Driver::rollbackTransaction(){    if (!isOpen() || isOpenError())        return false;    QSqlQuery q(createQuery());    if (!q.exec("ROLLBACK")) {        setLastError(QSqlError("Unable to begin transaction",                               q.lastError().databaseText(), QSqlError::Transaction));        return false;    }    return true;}QStringList QSQLite3Driver::tables(const QString &typeName) const{    QStringList res;    if (!isOpen())        return res;    int type = typeName.toInt();    QSqlQuery q = createQuery();    q.setForwardOnly(TRUE);#if (QT_VERSION-0 >= 0x030200)    if ((type & (int)QSql::Tables) && (type & (int)QSql::Views))        q.exec("SELECT name FROM sqlite_master WHERE type='table' OR type='view'");    else if (typeName.isEmpty() || (type & (int)QSql::Tables))        q.exec("SELECT name FROM sqlite_master WHERE type='table'");    else if (type & (int)QSql::Views)        q.exec("SELECT name FROM sqlite_master WHERE type='view'");#else        q.exec("SELECT name FROM sqlite_master WHERE type='table' OR type='view'");#endif    if (q.isActive()) {        while(q.next())            res.append(q.value(0).toString());    }#if (QT_VERSION-0 >= 0x030200)    if (type & (int)QSql::SystemTables) {        // there are no internal tables beside this one:        res.append("sqlite_master");    }#endif    return res;}QSqlIndex QSQLite3Driver::primaryIndex(const QString &tblname) const{    QSqlRecordInfo rec(recordInfo(tblname)); // expensive :(    if (!isOpen())        return QSqlIndex();    QSqlQuery q = createQuery();    q.setForwardOnly(TRUE);    // finrst find a UNIQUE INDEX    q.exec("PRAGMA index_list('" + tblname + "');");    QString indexname;    while(q.next()) {	if (q.value(2).toInt()==1) {	    indexname = q.value(1).toString();	    break;	}    }    if (indexname.isEmpty())	return QSqlIndex();    q.exec("PRAGMA index_info('" + indexname + "');");    QSqlIndex index(indexname);    while(q.next()) {	QString name = q.value(2).toString();	QSqlVariant::Type type = QSqlVariant::Invalid;	if (rec.contains(name))	    type = rec.find(name).type();	index.append(QSqlField(name, type));    }    return index;}QSqlRecordInfo QSQLite3Driver::recordInfo(const QString &tbl) const{    if (!isOpen())        return QSqlRecordInfo();    QSqlQuery q = createQuery();    q.setForwardOnly(TRUE);    q.exec("SELECT * FROM " + tbl + " LIMIT 1");    return recordInfo(q);}QSqlRecord QSQLite3Driver::record(const QString &tblname) const{    if (!isOpen())        return QSqlRecord();    return recordInfo(tblname).toRecord();}QSqlRecord QSQLite3Driver::record(const QSqlQuery& query) const{    if (query.isActive() && query.driver() == this) {        QSQLite3Result* result = (QSQLite3Result*)query.result();        return result->d->rInf;    }    return QSqlRecord();}QSqlRecordInfo QSQLite3Driver::recordInfo(const QSqlQuery& query) const{    if (query.isActive() && query.driver() == this) {        QSQLite3Result* result = (QSQLite3Result*)query.result();        return QSqlRecordInfo(result->d->rInf);    }    return QSqlRecordInfo();}

⌨️ 快捷键说明

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