summaryrefslogtreecommitdiffstats
path: root/kexi/kexidb/drivers/sqlite/sqliteconnection.cpp
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /kexi/kexidb/drivers/sqlite/sqliteconnection.cpp
downloadkoffice-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.cpp414
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"