diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/kexidb/drivers/sqlite/sqliteconnection.cpp | |
download | koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip |
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'kexi/kexidb/drivers/sqlite/sqliteconnection.cpp')
-rw-r--r-- | kexi/kexidb/drivers/sqlite/sqliteconnection.cpp | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/kexi/kexidb/drivers/sqlite/sqliteconnection.cpp b/kexi/kexidb/drivers/sqlite/sqliteconnection.cpp new file mode 100644 index 00000000..6de41c59 --- /dev/null +++ b/kexi/kexidb/drivers/sqlite/sqliteconnection.cpp @@ -0,0 +1,414 @@ +/* This file is part of the KDE project + Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl> + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this program; see the file COPYING. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301, USA. +*/ + +#include "sqliteconnection.h" +#include "sqliteconnection_p.h" +#include "sqlitecursor.h" +#include "sqlitepreparedstatement.h" + +#include "sqlite.h" + +#ifndef SQLITE2 +# include "kexisql.h" //for isReadOnly() +#endif + +#include <kexidb/driver.h> +#include <kexidb/cursor.h> +#include <kexidb/error.h> +#include <kexiutils/utils.h> + +#include <qfile.h> +#include <qdir.h> +#include <qregexp.h> + +#include <kgenericfactory.h> +#include <kdebug.h> + +//remove debug +#undef KexiDBDrvDbg +#define KexiDBDrvDbg if (0) kdDebug() + +using namespace KexiDB; + +SQLiteConnectionInternal::SQLiteConnectionInternal(Connection *connection) + : ConnectionInternal(connection) + , data(0) + , data_owned(true) + , errmsg_p(0) + , res(SQLITE_OK) + , temp_st(0x10000) +#ifdef SQLITE3 + , result_name(0) +#endif +{ +} + +SQLiteConnectionInternal::~SQLiteConnectionInternal() +{ + if (data_owned && data) { + free( data ); + data = 0; + } +//sqlite_freemem does this if (errmsg) { +// free( errmsg ); +// errmsg = 0; +// } +} + +void SQLiteConnectionInternal::storeResult() +{ + if (errmsg_p) { + errmsg = errmsg_p; + sqlite_free(errmsg_p); + errmsg_p = 0; + } +#ifdef SQLITE3 + errmsg = (data && res!=SQLITE_OK) ? sqlite3_errmsg(data) : 0; +#endif +} + +/*! Used by driver */ +SQLiteConnection::SQLiteConnection( Driver *driver, ConnectionData &conn_data ) + : Connection( driver, conn_data ) + ,d(new SQLiteConnectionInternal(this)) +{ +} + +SQLiteConnection::~SQLiteConnection() +{ + KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection()" << endl; + //disconnect if was connected +// disconnect(); + destroy(); + delete d; + KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection() ok" << endl; +} + +bool SQLiteConnection::drv_connect(KexiDB::ServerVersionInfo& version) +{ + KexiDBDrvDbg << "SQLiteConnection::connect()" << endl; + version.string = QString(SQLITE_VERSION); //defined in sqlite3.h + QRegExp re("(\\d+)\\.(\\d+)\\.(\\d+)"); + if (re.exactMatch(version.string)) { + version.major = re.cap(1).toUInt(); + version.minor = re.cap(2).toUInt(); + version.release = re.cap(3).toUInt(); + } + return true; +} + +bool SQLiteConnection::drv_disconnect() +{ + KexiDBDrvDbg << "SQLiteConnection::disconnect()" << endl; + return true; +} + +bool SQLiteConnection::drv_getDatabasesList( QStringList &list ) +{ + //this is one-db-per-file database + list.append( data()->fileName() ); //more consistent than dbFileName() ? + return true; +} + +bool SQLiteConnection::drv_containsTable( const QString &tableName ) +{ + bool success; + return resultExists(QString("select name from sqlite_master where type='table' and name LIKE %1") + .arg(driver()->escapeString(tableName)), success) && success; +} + +bool SQLiteConnection::drv_getTablesList( QStringList &list ) +{ + KexiDB::Cursor *cursor; + m_sql = "select lower(name) from sqlite_master where type='table'"; + if (!(cursor = executeQuery( m_sql ))) { + KexiDBWarn << "Connection::drv_getTablesList(): !executeQuery()" << endl; + return false; + } + list.clear(); + cursor->moveFirst(); + while (!cursor->eof() && !cursor->error()) { + list += cursor->value(0).toString(); + cursor->moveNext(); + } + if (cursor->error()) { + deleteCursor(cursor); + return false; + } + return deleteCursor(cursor); +} + +bool SQLiteConnection::drv_createDatabase( const QString &dbName ) +{ + // SQLite creates a new db is it does not exist + return drv_useDatabase(dbName); +#if 0 + d->data = sqlite_open( QFile::encodeName( data()->fileName() ), 0/*mode: unused*/, + &d->errmsg_p ); + d->storeResult(); + return d->data != 0; +#endif +} + +bool SQLiteConnection::drv_useDatabase( const QString &dbName, bool *cancelled, + MessageHandler* msgHandler ) +{ + Q_UNUSED(dbName); +// KexiDBDrvDbg << "drv_useDatabase(): " << data()->fileName() << endl; +#ifdef SQLITE2 + Q_UNUSED(cancelled); + Q_UNUSED(msgHandler); + d->data = sqlite_open( QFile::encodeName( data()->fileName() ), 0/*mode: unused*/, + &d->errmsg_p ); + d->storeResult(); + return d->data != 0; +#else //SQLITE3 + //TODO: perhaps allow to use sqlite3_open16() as well for SQLite ~ 3.3 ? +//! @todo add option (command line or in kexirc?) + int exclusiveFlag = Connection::isReadOnly() ? SQLITE_OPEN_READONLY : SQLITE_OPEN_WRITE_LOCKED; // <-- shared read + (if !r/o): exclusive write +//! @todo add option + int allowReadonly = 1; + const bool wasReadOnly = Connection::isReadOnly(); + + d->res = sqlite3_open( + //QFile::encodeName( data()->fileName() ), + data()->fileName().utf8(), /* unicode expected since SQLite 3.1 */ + &d->data, + exclusiveFlag, + allowReadonly /* If 1 and locking fails, try opening in read-only mode */ + ); + d->storeResult(); + + if (d->res == SQLITE_OK && cancelled && !wasReadOnly && allowReadonly && isReadOnly()) { + //opened as read only, ask + if (KMessageBox::Continue != + askQuestion( + i18n("Do you want to open file \"%1\" as read-only?") + .arg(QDir::convertSeparators(data()->fileName())) + + "\n\n" + + i18n("The file is probably already open on this or another computer.") + " " + + i18n("Could not gain exclusive access for writing the file."), + KMessageBox::WarningContinueCancel, KMessageBox::Continue, + KGuiItem(i18n("Open As Read-Only"), "fileopen"), KStdGuiItem::cancel(), + "askBeforeOpeningFileReadOnly", KMessageBox::Notify, msgHandler )) + { + clearError(); + if (!drv_closeDatabase()) + return false; + *cancelled = true; + return false; + } + } + + if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_READWRITE) { + setError(ERR_ACCESS_RIGHTS, + i18n("The file is probably already open on this or another computer.")+"\n\n" + + i18n("Could not gain exclusive access for reading and writing the file.") + " " + + i18n("Check the file's permissions and whether it is already opened and locked by another application.")); + } + else if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_WRITE) { + setError(ERR_ACCESS_RIGHTS, + i18n("The file is probably already open on this or another computer.")+"\n\n" + + i18n("Could not gain exclusive access for writing the file.") + " " + + i18n("Check the file's permissions and whether it is already opened and locked by another application.")); + } + return d->res == SQLITE_OK; +#endif +} + +bool SQLiteConnection::drv_closeDatabase() +{ + if (!d->data) + return false; + +#ifdef SQLITE2 + sqlite_close(d->data); + d->data = 0; + return true; +#else + const int res = sqlite_close(d->data); + if (SQLITE_OK == res) { + d->data = 0; + return true; + } + if (SQLITE_BUSY==res) { +#if 0 //this is ANNOYING, needs fixing (by closing cursors or waiting) + setError(ERR_CLOSE_FAILED, i18n("Could not close busy database.")); +#else + return true; +#endif + } + return false; +#endif +} + +bool SQLiteConnection::drv_dropDatabase( const QString &dbName ) +{ + Q_UNUSED(dbName); // Each database is one single SQLite file. + const QString filename = data()->fileName(); + if (QFile(filename).exists() && !QDir().remove(filename)) { + setError(ERR_ACCESS_RIGHTS, i18n("Could not remove file \"%1\".") + .arg(QDir::convertSeparators(filename)) + " " + + i18n("Check the file's permissions and whether it is already opened and locked by another application.")); + return false; + } + return true; +} + +//CursorData* SQLiteConnection::drv_createCursor( const QString& statement ) +Cursor* SQLiteConnection::prepareQuery( const QString& statement, uint cursor_options ) +{ + return new SQLiteCursor( this, statement, cursor_options ); +} + +Cursor* SQLiteConnection::prepareQuery( QuerySchema& query, uint cursor_options ) +{ + return new SQLiteCursor( this, query, cursor_options ); +} + +bool SQLiteConnection::drv_executeSQL( const QString& statement ) +{ +// KexiDBDrvDbg << "SQLiteConnection::drv_executeSQL(" << statement << ")" <<endl; +// QCString st(statement.length()*2); +// st = escapeString( statement.local8Bit() ); //? +#ifdef SQLITE_UTF8 + d->temp_st = statement.utf8(); +#else + d->temp_st = statement.local8Bit(); //latin1 only +#endif + +#ifdef KEXI_DEBUG_GUI + KexiUtils::addKexiDBDebug(QString("ExecuteSQL (SQLite): ")+statement); +#endif + + d->res = sqlite_exec( + d->data, + (const char*)d->temp_st, + 0/*callback*/, + 0, + &d->errmsg_p ); + d->storeResult(); +#ifdef KEXI_DEBUG_GUI + KexiUtils::addKexiDBDebug(d->res==SQLITE_OK ? " Success" : " Failure"); +#endif + return d->res==SQLITE_OK; +} + +Q_ULLONG SQLiteConnection::drv_lastInsertRowID() +{ + return (Q_ULLONG)sqlite_last_insert_rowid(d->data); +} + +int SQLiteConnection::serverResult() +{ + return d->res==0 ? Connection::serverResult() : d->res; +} + +QString SQLiteConnection::serverResultName() +{ + QString r = +#ifdef SQLITE2 + QString::fromLatin1( sqlite_error_string(d->res) ); +#else //SQLITE3 + QString::null; //fromLatin1( d->result_name ); +#endif + return r.isEmpty() ? Connection::serverResultName() : r; +} + +void SQLiteConnection::drv_clearServerResult() +{ + if (!d) + return; + d->res = SQLITE_OK; +#ifdef SQLITE2 + d->errmsg_p = 0; +#else +// d->result_name = 0; +#endif +} + +QString SQLiteConnection::serverErrorMsg() +{ + return d->errmsg.isEmpty() ? Connection::serverErrorMsg() : d->errmsg; +} + +PreparedStatement::Ptr SQLiteConnection::prepareStatement(PreparedStatement::StatementType type, + FieldList& fields) +{ +//#ifndef SQLITE2 //TEMP IFDEF! + return new SQLitePreparedStatement(type, *d, fields); +//#endif +} + +bool SQLiteConnection::isReadOnly() const +{ +#ifdef SQLITE2 + return Connection::isReadOnly(); +#else + return d->data ? sqlite3_is_readonly(d->data) : false; +#endif +} + +#ifdef SQLITE2 +bool SQLiteConnection::drv_alterTableName(TableSchema& tableSchema, const QString& newName, bool replace) +{ + const QString oldTableName = tableSchema.name(); + const bool destTableExists = this->tableSchema( newName ) != 0; + + //1. drop the table + if (destTableExists) { + if (!replace) + return false; + if (!drv_dropTable( newName )) + return false; + } + + //2. create a copy of the table +//TODO: move this code to drv_copyTable() + tableSchema.setName(newName); + +//helper: +#define drv_alterTableName_ERR \ + tableSchema.setName(oldTableName) //restore old name + + if (!drv_createTable( tableSchema )) { + drv_alterTableName_ERR; + return false; + } + +//TODO indices, etc.??? + + // 3. copy all rows to the new table + if (!executeSQL(QString::fromLatin1("INSERT INTO %1 SELECT * FROM %2") + .arg(escapeIdentifier(tableSchema.name())).arg(escapeIdentifier(oldTableName)))) + { + drv_alterTableName_ERR; + return false; + } + + // 4. drop old table. + if (!drv_dropTable( oldTableName )) { + drv_alterTableName_ERR; + return false; + } + return true; +} +#endif + +#include "sqliteconnection.moc" |