kexi

sqliteconnection.cpp

00001 /* This file is part of the KDE project
00002    Copyright (C) 2003-2006 Jaroslaw Staniek <js@iidea.pl>
00003 
00004    This program is free software; you can redistribute it and/or
00005    modify it under the terms of the GNU Library General Public
00006    License as published by the Free Software Foundation; either
00007    version 2 of the License, or (at your option) any later version.
00008 
00009    This program is distributed in the hope that it will be useful,
00010    but WITHOUT ANY WARRANTY; without even the implied warranty of
00011    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012    Library General Public License for more details.
00013 
00014    You should have received a copy of the GNU Library General Public License
00015    along with this program; see the file COPYING.  If not, write to
00016    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00017  * Boston, MA 02110-1301, USA.
00018 */
00019 
00020 #include "sqliteconnection.h"
00021 #include "sqliteconnection_p.h"
00022 #include "sqlitecursor.h"
00023 #include "sqlitepreparedstatement.h"
00024 
00025 #include "sqlite.h"
00026 
00027 #ifndef SQLITE2
00028 # include "kexisql.h" //for isReadOnly()
00029 #endif
00030 
00031 #include <kexidb/driver.h>
00032 #include <kexidb/cursor.h>
00033 #include <kexidb/error.h>
00034 
00035 #include <qfile.h>
00036 #include <qdir.h>
00037 
00038 #include <kgenericfactory.h>
00039 #include <kdebug.h>
00040 
00041 //remove debug
00042 #undef KexiDBDrvDbg
00043 #define KexiDBDrvDbg if (0) kdDebug()
00044 
00045 using namespace KexiDB;
00046 
00047 SQLiteConnectionInternal::SQLiteConnectionInternal(Connection *connection)
00048  : ConnectionInternal(connection)
00049  , data(0)
00050  , data_owned(true)
00051  , errmsg_p(0)
00052  , res(SQLITE_OK)
00053  , temp_st(0x10000)
00054 #ifdef SQLITE3
00055  , result_name(0)
00056 #endif
00057 {
00058 }
00059 
00060 SQLiteConnectionInternal::~SQLiteConnectionInternal() 
00061 {
00062     if (data_owned && data) {
00063         free( data ); 
00064         data = 0;
00065     }
00066 //sqlite_freemem does this  if (errmsg) {
00067 //      free( errmsg );
00068 //      errmsg = 0;
00069 //  }
00070 }
00071 
00072 void SQLiteConnectionInternal::storeResult()
00073 {
00074     if (errmsg_p) {
00075         errmsg = errmsg_p;
00076         sqlite_free(errmsg_p);
00077         errmsg_p = 0;
00078     }
00079 #ifdef SQLITE3
00080     errmsg = (data && res!=SQLITE_OK) ? sqlite3_errmsg(data) : 0;
00081 #endif
00082 }
00083 
00085 SQLiteConnection::SQLiteConnection( Driver *driver, ConnectionData &conn_data )
00086     : Connection( driver, conn_data )
00087     ,d(new SQLiteConnectionInternal(this))
00088 {
00089 }
00090 
00091 SQLiteConnection::~SQLiteConnection()
00092 {
00093     KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection()" << endl;
00094     //disconnect if was connected
00095 //  disconnect();
00096     destroy();
00097     delete d;
00098     KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection() ok" << endl;
00099 }
00100 
00101 bool SQLiteConnection::drv_connect()
00102 {
00103     KexiDBDrvDbg << "SQLiteConnection::connect()" << endl;
00104     return true;
00105 }
00106 
00107 bool SQLiteConnection::drv_disconnect()
00108 {
00109     KexiDBDrvDbg << "SQLiteConnection::disconnect()" << endl;
00110     return true;
00111 }
00112 
00113 bool SQLiteConnection::drv_getDatabasesList( QStringList &list )
00114 {
00115     //this is one-db-per-file database
00116     list.append( m_data->fileName() ); //more consistent than dbFileName() ?
00117     return true;
00118 }
00119 
00120 bool SQLiteConnection::drv_containsTable( const QString &tableName )
00121 {
00122     bool success;
00123     return resultExists(QString("select name from sqlite_master where type='table' and name LIKE %1")
00124         .arg(driver()->escapeString(tableName)), success) && success;
00125 }
00126 
00127 bool SQLiteConnection::drv_getTablesList( QStringList &list )
00128 {
00129     KexiDB::Cursor *cursor;
00130     m_sql = "select lower(name) from sqlite_master where type='table'";
00131     if (!(cursor = executeQuery( m_sql ))) {
00132         KexiDBWarn << "Connection::drv_getTablesList(): !executeQuery()" << endl;
00133         return false;
00134     }
00135     list.clear();
00136     cursor->moveFirst();
00137     while (!cursor->eof() && !cursor->error()) {
00138         list += cursor->value(0).toString();
00139         cursor->moveNext();
00140     }
00141     if (cursor->error()) {
00142         deleteCursor(cursor);
00143         return false;
00144     }
00145     return deleteCursor(cursor);
00146 }
00147 
00148 bool SQLiteConnection::drv_createDatabase( const QString &dbName )
00149 {
00150     // SQLite creates a new db is it does not exist
00151     return drv_useDatabase(dbName);
00152 #if 0
00153     d->data = sqlite_open( QFile::encodeName( m_data->fileName() ), 0/*mode: unused*/, 
00154         &d->errmsg_p );
00155     d->storeResult();
00156     return d->data != 0;
00157 #endif
00158 }
00159 
00160 bool SQLiteConnection::drv_useDatabase( const QString &dbName, bool *cancelled, 
00161     MessageHandler* msgHandler )
00162 {
00163     Q_UNUSED(dbName);
00164 #ifndef KEXI_FUTURE_FEATURES
00165     Q_UNUSED(cancelled);
00166     Q_UNUSED(msgHandler);
00167 #endif
00168 //  KexiDBDrvDbg << "drv_useDatabase(): " << m_data->fileName() << endl;
00169 #ifdef SQLITE2
00170     d->data = sqlite_open( QFile::encodeName( m_data->fileName() ), 0/*mode: unused*/, 
00171         &d->errmsg_p );
00172     d->storeResult();
00173     return d->data != 0;
00174 #else //SQLITE3
00175     //TODO: perhaps allow to use sqlite3_open16() as well for SQLite ~ 3.3 ?
00177     int exclusiveFlag = Connection::isReadOnly() ? SQLITE_OPEN_READONLY : SQLITE_OPEN_WRITE_LOCKED; // <-- shared read + (if !r/o): exclusive write
00179     int allowReadonly = 1;
00180 # ifdef KEXI_FUTURE_FEATURES
00181     const bool wasReadOnly = Connection::isReadOnly();
00182 # endif
00183 
00184     d->res = sqlite3_open( 
00185         //m_data->fileName().ucs2(), //utf16
00186         QFile::encodeName( m_data->fileName() ), 
00187         &d->data,
00188         exclusiveFlag,
00189         allowReadonly /* If 1 and locking fails, try opening in read-only mode */
00190     );
00191     d->storeResult();
00192 
00193 #ifdef KEXI_FUTURE_FEATURES
00194     if (d->res == SQLITE_OK && cancelled && !wasReadOnly && allowReadonly && isReadOnly()) {
00195         //opened as read only, ask
00196         if (KMessageBox::Continue != 
00197             askQuestion( 
00198             futureI18n("Do you want to open file \"%1\" as read-only?")
00199                 .arg(QDir::convertSeparators(m_data->fileName()))
00200             + "\n\n"
00201             + i18n("The file is probably already open on this or another computer.") + " "
00202             + i18n("Could not gain exclusive access for writing the file."),
00203             KMessageBox::WarningContinueCancel, KMessageBox::Continue, 
00204             KGuiItem(futureI18n("Open As Read-Only"), "fileopen"), KStdGuiItem::cancel(),
00205             "askBeforeOpeningFileReadOnly", KMessageBox::Notify, msgHandler ))
00206         {
00207             clearError();
00208             if (!drv_closeDatabase())
00209                 return false;
00210             *cancelled = true;
00211             return false;
00212         }
00213     }
00214 #endif
00215 
00216     if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_READWRITE) {
00217         setError(ERR_ACCESS_RIGHTS, 
00218         i18n("The file is probably already open on this or another computer.")+"\n\n"
00219         + i18n("Could not gain exclusive access for reading and writing the file.") + " "
00220         + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
00221     }
00222     else if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_WRITE) {
00223         setError(ERR_ACCESS_RIGHTS, 
00224         i18n("The file is probably already open on this or another computer.")+"\n\n"
00225         + i18n("Could not gain exclusive access for writing the file.") + " "
00226         + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
00227     }
00228     return d->res == SQLITE_OK;
00229 #endif
00230 }
00231 
00232 bool SQLiteConnection::drv_closeDatabase()
00233 {
00234     if (!d->data)
00235         return false;
00236 
00237 #ifdef SQLITE2
00238     sqlite_close(d->data);
00239     d->data = 0;
00240     return true;
00241 #else
00242     const int res = sqlite_close(d->data);
00243     if (SQLITE_OK == res) {
00244         d->data = 0;
00245         return true;
00246     }
00247     if (SQLITE_BUSY==res) {
00248         setError(ERR_OTHER);
00249     }
00250     return false;
00251 #endif
00252 }
00253 
00254 bool SQLiteConnection::drv_dropDatabase( const QString &dbName )
00255 {
00256     if (QFile(m_data->fileName()).exists() && !QDir().remove(m_data->fileName())) {
00257         setError(ERR_ACCESS_RIGHTS, i18n("Could not remove file \"%1\".")
00258             .arg(QDir::convertSeparators(dbName)) + " "
00259             + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
00260         return false;
00261     }
00262     return true;
00263 }
00264 
00265 //CursorData* SQLiteConnection::drv_createCursor( const QString& statement )
00266 Cursor* SQLiteConnection::prepareQuery( const QString& statement, uint cursor_options )
00267 {
00268     return new SQLiteCursor( this, statement, cursor_options );
00269 }
00270 
00271 Cursor* SQLiteConnection::prepareQuery( QuerySchema& query, uint cursor_options )
00272 {
00273     return new SQLiteCursor( this, query, cursor_options );
00274 }
00275 
00276 bool SQLiteConnection::drv_executeSQL( const QString& statement )
00277 {
00278 //  KexiDBDrvDbg << "SQLiteConnection::drv_executeSQL(" << statement << ")" <<endl;
00279 //  QCString st(statement.length()*2);
00280 //  st = escapeString( statement.local8Bit() ); //?
00281 #ifdef SQLITE_UTF8
00282     d->temp_st = statement.utf8();
00283 #else
00284     d->temp_st = statement.local8Bit(); //latin1 only
00285 #endif
00286 
00287     d->res = sqlite_exec( 
00288         d->data, 
00289         (const char*)d->temp_st, 
00290         0/*callback*/, 
00291         0,
00292         &d->errmsg_p );
00293     d->storeResult();
00294     return d->res==SQLITE_OK;
00295 }
00296 
00297 Q_ULLONG SQLiteConnection::drv_lastInsertRowID()
00298 {
00299     return (Q_ULLONG)sqlite_last_insert_rowid(d->data);
00300 }
00301 
00302 int SQLiteConnection::serverResult()
00303 {
00304     return d->res==0 ? Connection::serverResult() : d->res;
00305 }
00306 
00307 QString SQLiteConnection::serverResultName()
00308 {
00309     QString r = 
00310 #ifdef SQLITE2
00311         QString::fromLatin1( sqlite_error_string(d->res) );
00312 #else //SQLITE3
00313         QString::null; //fromLatin1( d->result_name );
00314 #endif
00315     return r.isEmpty() ? Connection::serverResultName() : r;
00316 }
00317 
00318 void SQLiteConnection::drv_clearServerResult()
00319 {
00320     if (!d)
00321         return;
00322     d->res = SQLITE_OK;
00323 #ifdef SQLITE2
00324     d->errmsg_p = 0;
00325 #else
00326 //  d->result_name = 0;
00327 #endif
00328 }
00329 
00330 QString SQLiteConnection::serverErrorMsg()
00331 {
00332     return d->errmsg.isEmpty() ? Connection::serverErrorMsg() : d->errmsg;
00333 }
00334 
00335 PreparedStatement::Ptr SQLiteConnection::prepareStatement(PreparedStatement::StatementType type, 
00336     FieldList& fields)
00337 {
00338 //#ifndef SQLITE2 //TEMP IFDEF!
00339     return new SQLitePreparedStatement(type, *d, fields);
00340 //#endif
00341 }
00342 
00343 bool SQLiteConnection::isReadOnly() const
00344 {
00345 #ifdef SQLITE2
00346     return Connection::isReadOnly();
00347 #else
00348     return d->data ? sqlite3_is_readonly(d->data) : false;
00349 #endif
00350 }
00351 
00352 #include "sqliteconnection.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys