?? qsql_sqlite.cpp
字號:
/******************************************************************************** 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_sqlite.h"#include <qcoreapplication.h>#include <qvariant.h>#include <qsqlerror.h>#include <qsqlfield.h>#include <qsqlindex.h>#include <qsqlquery.h>#include <qstringlist.h>#include <qvector.h>#include <qdebug.h>#if defined Q_OS_WIN# include <qt_windows.h>#else# include <unistd.h>#endif#include <sqlite3.h>Q_DECLARE_METATYPE(sqlite3*)Q_DECLARE_METATYPE(sqlite3_stmt*)static QVariant::Type qGetColumnType(const QString &tpName){ const QString typeName = tpName.toLower(); if (typeName == QLatin1String("integer") || typeName == QLatin1String("int")) return QVariant::Int; if (typeName == QLatin1String("double") || typeName == QLatin1String("float") || typeName.startsWith(QLatin1String("numeric"))) return QVariant::Double; if (typeName == QLatin1String("blob")) return QVariant::ByteArray; return QVariant::String;}static QSqlError qMakeError(sqlite3 *access, const QString &descr, QSqlError::ErrorType type, int errorCode = -1){ return QSqlError(descr, QString::fromUtf16(static_cast<const ushort *>(sqlite3_errmsg16(access))), type, errorCode);}class QSQLiteDriverPrivate{public: inline QSQLiteDriverPrivate() : access(0) {} sqlite3 *access;};class QSQLiteResultPrivate{public: QSQLiteResultPrivate(QSQLiteResult *res); void cleanup(); bool fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch); // initializes the recordInfo and the cache void initColumns(bool emptyResultset); void finalize(); QSQLiteResult* 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;QSQLiteResultPrivate::QSQLiteResultPrivate(QSQLiteResult* res) : q(res), access(0), stmt(0), skippedStatus(false), skipRow(false), utf8(false){}void QSQLiteResultPrivate::cleanup(){ finalize(); rInf.clear(); skippedStatus = false; skipRow = false; q->setAt(QSql::BeforeFirstRow); q->setActive(false); q->cleanup();}void QSQLiteResultPrivate::finalize(){ if (!stmt) return; sqlite3_finalize(stmt); stmt = 0;}void QSQLiteResultPrivate::initColumns(bool emptyResultset){ 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::fromUtf16( static_cast<const ushort *>(sqlite3_column_name16(stmt, i))); // must use typeName for resolving the type to match QSqliteDriver::record QString typeName = QString::fromUtf16( static_cast<const ushort *>(sqlite3_column_decltype16(stmt, i))); int dotIdx = colName.lastIndexOf(QLatin1Char('.')); QSqlField fld(colName.mid(dotIdx == -1 ? 0 : dotIdx + 1), qGetColumnType(typeName)); // sqlite3_column_type is documented to have undefined behavior if the result set is empty int stp = emptyResultset ? -1 : sqlite3_column_type(stmt, i); fld.setSqlType(stp); rInf.append(fld); }}bool QSQLiteResultPrivate::fetchNext(QSqlCachedResult::ValueCache &values, int idx, bool initialFetch){ int res; int i; if (skipRow) { // already fetched Q_ASSERT(!initialFetch); skipRow = false; return skippedStatus; } skipRow = initialFetch; res = sqlite3_step(stmt); switch(res) { case SQLITE_ROW: // check to see if should fill out columns if (rInf.isEmpty()) // must be first call. initColumns(false); if (idx < 0 && !initialFetch) return true; for (i = 0; i < rInf.count(); ++i) { switch (sqlite3_column_type(stmt, i)) { case SQLITE_BLOB: values[i + idx] = QByteArray(static_cast<const char *>( sqlite3_column_blob(stmt, i)), sqlite3_column_bytes(stmt, i)); break; case SQLITE_INTEGER: values[i + idx] = sqlite3_column_int64(stmt, i); break; case SQLITE_FLOAT: values[i + idx] = sqlite3_column_double(stmt, i); break; case SQLITE_NULL: values[i + idx] = QVariant(QVariant::String); break; default: values[i + idx] = QString::fromUtf16(static_cast<const ushort *>( sqlite3_column_text16(stmt, i)), sqlite3_column_bytes16(stmt, i) / sizeof(ushort)); break; } } return true; case SQLITE_DONE: if (rInf.isEmpty()) // must be first call. initColumns(true); q->setAt(QSql::AfterLastRow); sqlite3_reset(stmt); return false; case SQLITE_ERROR: case SQLITE_MISUSE: case SQLITE_BUSY: default: // something wrong, don't get col info, but still return false q->setLastError(qMakeError(access, QCoreApplication::translate("QSQLiteResult", "Unable to fetch row"), QSqlError::ConnectionError, res)); sqlite3_reset(stmt); q->setAt(QSql::AfterLastRow); return false; } return false;}QSQLiteResult::QSQLiteResult(const QSQLiteDriver* db) : QSqlCachedResult(db){ d = new QSQLiteResultPrivate(this); d->access = db->d->access;}QSQLiteResult::~QSQLiteResult(){ d->cleanup(); delete d;}bool QSQLiteResult::reset(const QString &query){ if (!prepare(query)) return false; return exec();}bool QSQLiteResult::prepare(const QString &query){ if (!driver() || !driver()->isOpen() || driver()->isOpenError()) return false; d->cleanup(); setSelect(false); int res = sqlite3_prepare16(d->access, query.constData(), (query.size() + 1) * sizeof(QChar), &d->stmt, 0); if (res != SQLITE_OK) { setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", "Unable to execute statement"), QSqlError::StatementError, res)); d->finalize(); return false; } return true;}bool QSQLiteResult::exec(){ const QVector<QVariant> values = boundValues(); d->skippedStatus = false; d->skipRow = false; clearValues(); setLastError(QSqlError()); int res = sqlite3_reset(d->stmt); if (res != SQLITE_OK) { setLastError(qMakeError(d->access, QCoreApplication::translate("QSQLiteResult", "Unable to reset statement"), QSqlError::StatementError, res)); d->finalize(); return false; } int paramCount = sqlite3_bind_parameter_count(d->stmt); if (paramCount == values.count()) { for (int i = 0; i < paramCount; ++i) { res = SQLITE_OK; const QVariant value = values.at(i); if (value.isNull()) { res = sqlite3_bind_null(d->stmt, i + 1); } else { switch (value.type()) { case QVariant::ByteArray: { const QByteArray *ba = static_cast<const QByteArray*>(value.constData()); res = sqlite3_bind_blob(d->stmt, i + 1, ba->constData(), ba->size(), SQLITE_STATIC); break; } case QVariant::Int: res = sqlite3_bind_int(d->stmt, i + 1, value.toInt()); break; case QVariant::Double: res = sqlite3_bind_double(d->stmt, i + 1, value.toDouble());
?? 快捷鍵說明
復(fù)制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -