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             *cancelled = true;
00209             return false;
00210         }
00211     }
00212 #endif
00213 
00214     if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_READWRITE) {
00215         setError(ERR_ACCESS_RIGHTS, 
00216         i18n("The file is probably already open on this or another computer.")+"\n\n"
00217         + i18n("Could not gain exclusive access for reading and writing the file.") + " "
00218         + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
00219     }
00220     else if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_WRITE) {
00221         setError(ERR_ACCESS_RIGHTS, 
00222         i18n("The file is probably already open on this or another computer.")+"\n\n"
00223         + i18n("Could not gain exclusive access for writing the file.") + " "
00224         + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
00225     }
00226     return d->res == SQLITE_OK;
00227 #endif
00228 }
00229 
00230 bool SQLiteConnection::drv_closeDatabase()
00231 {
00232     if (!d->data)
00233         return false;
00234     sqlite_close(d->data);
00235     d->data = 0;
00236     return true;
00237 }
00238 
00239 bool SQLiteConnection::drv_dropDatabase( const QString &dbName )
00240 {
00241     if (QFile(m_data->fileName()).exists() && !QDir().remove(m_data->fileName())) {
00242         setError(ERR_ACCESS_RIGHTS, i18n("Could not remove file \"%1\".")
00243             .arg(QDir::convertSeparators(dbName)) + " "
00244             + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
00245         return false;
00246     }
00247     return true;
00248 }
00249 
00250 //CursorData* SQLiteConnection::drv_createCursor( const QString& statement )
00251 Cursor* SQLiteConnection::prepareQuery( const QString& statement, uint cursor_options )
00252 {
00253     return new SQLiteCursor( this, statement, cursor_options );
00254 }
00255 
00256 Cursor* SQLiteConnection::prepareQuery( QuerySchema& query, uint cursor_options )
00257 {
00258     return new SQLiteCursor( this, query, cursor_options );
00259 }
00260 
00261 bool SQLiteConnection::drv_executeSQL( const QString& statement )
00262 {
00263 //  KexiDBDrvDbg << "SQLiteConnection::drv_executeSQL(" << statement << ")" <<endl;
00264 //  QCString st(statement.length()*2);
00265 //  st = escapeString( statement.local8Bit() ); //?
00266 #ifdef SQLITE_UTF8
00267     d->temp_st = statement.utf8();
00268 #else
00269     d->temp_st = statement.local8Bit(); //latin1 only
00270 #endif
00271 
00272     d->res = sqlite_exec( 
00273         d->data, 
00274         (const char*)d->temp_st, 
00275         0/*callback*/, 
00276         0,
00277         &d->errmsg_p );
00278     d->storeResult();
00279     return d->res==SQLITE_OK;
00280 }
00281 
00282 Q_ULLONG SQLiteConnection::drv_lastInsertRowID()
00283 {
00284     return (Q_ULLONG)sqlite_last_insert_rowid(d->data);
00285 }
00286 
00287 int SQLiteConnection::serverResult()
00288 {
00289     return d->res==0 ? Connection::serverResult() : d->res;
00290 }
00291 
00292 QString SQLiteConnection::serverResultName()
00293 {
00294     QString r = 
00295 #ifdef SQLITE2
00296         QString::fromLatin1( sqlite_error_string(d->res) );
00297 #else //SQLITE3
00298         QString::null; //fromLatin1( d->result_name );
00299 #endif
00300     return r.isEmpty() ? Connection::serverResultName() : r;
00301 }
00302 
00303 void SQLiteConnection::drv_clearServerResult()
00304 {
00305     if (!d)
00306         return;
00307     d->res = SQLITE_OK;
00308 #ifdef SQLITE2
00309     d->errmsg_p = 0;
00310 #else
00311 //  d->result_name = 0;
00312 #endif
00313 }
00314 
00315 QString SQLiteConnection::serverErrorMsg()
00316 {
00317     return d->errmsg.isEmpty() ? Connection::serverErrorMsg() : d->errmsg;
00318 }
00319 
00320 PreparedStatement::Ptr SQLiteConnection::prepareStatement(PreparedStatement::StatementType type, 
00321     FieldList& fields)
00322 {
00323 //#ifndef SQLITE2 //TEMP IFDEF!
00324     return new SQLitePreparedStatement(type, *d, fields);
00325 //#endif
00326 }
00327 
00328 bool SQLiteConnection::isReadOnly() const
00329 {
00330 #ifdef SQLITE2
00331     return Connection::isReadOnly();
00332 #else
00333     return d->data ? sqlite3_is_readonly(d->data) : false;
00334 #endif
00335 }
00336 
00337 #include "sqliteconnection.moc"
KDE Home | KDE Accessibility Home | Description of Access Keys