00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
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"
00029 #endif
00030
00031 #include <kexidb/driver.h>
00032 #include <kexidb/cursor.h>
00033 #include <kexidb/error.h>
00034 #include <kexiutils/utils.h>
00035
00036 #include <qfile.h>
00037 #include <qdir.h>
00038 #include <qregexp.h>
00039
00040 #include <kgenericfactory.h>
00041 #include <kdebug.h>
00042
00043
00044 #undef KexiDBDrvDbg
00045 #define KexiDBDrvDbg if (0) kdDebug()
00046
00047 using namespace KexiDB;
00048
00049 SQLiteConnectionInternal::SQLiteConnectionInternal(Connection *connection)
00050 : ConnectionInternal(connection)
00051 , data(0)
00052 , data_owned(true)
00053 , errmsg_p(0)
00054 , res(SQLITE_OK)
00055 , temp_st(0x10000)
00056 #ifdef SQLITE3
00057 , result_name(0)
00058 #endif
00059 {
00060 }
00061
00062 SQLiteConnectionInternal::~SQLiteConnectionInternal()
00063 {
00064 if (data_owned && data) {
00065 free( data );
00066 data = 0;
00067 }
00068
00069
00070
00071
00072 }
00073
00074 void SQLiteConnectionInternal::storeResult()
00075 {
00076 if (errmsg_p) {
00077 errmsg = errmsg_p;
00078 sqlite_free(errmsg_p);
00079 errmsg_p = 0;
00080 }
00081 #ifdef SQLITE3
00082 errmsg = (data && res!=SQLITE_OK) ? sqlite3_errmsg(data) : 0;
00083 #endif
00084 }
00085
00087 SQLiteConnection::SQLiteConnection( Driver *driver, ConnectionData &conn_data )
00088 : Connection( driver, conn_data )
00089 ,d(new SQLiteConnectionInternal(this))
00090 {
00091 }
00092
00093 SQLiteConnection::~SQLiteConnection()
00094 {
00095 KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection()" << endl;
00096
00097
00098 destroy();
00099 delete d;
00100 KexiDBDrvDbg << "SQLiteConnection::~SQLiteConnection() ok" << endl;
00101 }
00102
00103 bool SQLiteConnection::drv_connect(KexiDB::ServerVersionInfo& version)
00104 {
00105 KexiDBDrvDbg << "SQLiteConnection::connect()" << endl;
00106 version.string = QString(SQLITE_VERSION);
00107 QRegExp re("(\\d+)\\.(\\d+)\\.(\\d+)");
00108 if (re.exactMatch(version.string)) {
00109 version.major = re.cap(1).toUInt();
00110 version.minor = re.cap(2).toUInt();
00111 version.release = re.cap(3).toUInt();
00112 }
00113 return true;
00114 }
00115
00116 bool SQLiteConnection::drv_disconnect()
00117 {
00118 KexiDBDrvDbg << "SQLiteConnection::disconnect()" << endl;
00119 return true;
00120 }
00121
00122 bool SQLiteConnection::drv_getDatabasesList( QStringList &list )
00123 {
00124
00125 list.append( data()->fileName() );
00126 return true;
00127 }
00128
00129 bool SQLiteConnection::drv_containsTable( const QString &tableName )
00130 {
00131 bool success;
00132 return resultExists(QString("select name from sqlite_master where type='table' and name LIKE %1")
00133 .arg(driver()->escapeString(tableName)), success) && success;
00134 }
00135
00136 bool SQLiteConnection::drv_getTablesList( QStringList &list )
00137 {
00138 KexiDB::Cursor *cursor;
00139 m_sql = "select lower(name) from sqlite_master where type='table'";
00140 if (!(cursor = executeQuery( m_sql ))) {
00141 KexiDBWarn << "Connection::drv_getTablesList(): !executeQuery()" << endl;
00142 return false;
00143 }
00144 list.clear();
00145 cursor->moveFirst();
00146 while (!cursor->eof() && !cursor->error()) {
00147 list += cursor->value(0).toString();
00148 cursor->moveNext();
00149 }
00150 if (cursor->error()) {
00151 deleteCursor(cursor);
00152 return false;
00153 }
00154 return deleteCursor(cursor);
00155 }
00156
00157 bool SQLiteConnection::drv_createDatabase( const QString &dbName )
00158 {
00159
00160 return drv_useDatabase(dbName);
00161 #if 0
00162 d->data = sqlite_open( QFile::encodeName( data()->fileName() ), 0,
00163 &d->errmsg_p );
00164 d->storeResult();
00165 return d->data != 0;
00166 #endif
00167 }
00168
00169 bool SQLiteConnection::drv_useDatabase( const QString &dbName, bool *cancelled,
00170 MessageHandler* msgHandler )
00171 {
00172 Q_UNUSED(dbName);
00173
00174 #ifdef SQLITE2
00175 Q_UNUSED(cancelled);
00176 Q_UNUSED(msgHandler);
00177 d->data = sqlite_open( QFile::encodeName( data()->fileName() ), 0,
00178 &d->errmsg_p );
00179 d->storeResult();
00180 return d->data != 0;
00181 #else //SQLITE3
00182
00184 int exclusiveFlag = Connection::isReadOnly() ? SQLITE_OPEN_READONLY : SQLITE_OPEN_WRITE_LOCKED;
00186 int allowReadonly = 1;
00187 const bool wasReadOnly = Connection::isReadOnly();
00188
00189 d->res = sqlite3_open(
00190
00191 data()->fileName().utf8(),
00192 &d->data,
00193 exclusiveFlag,
00194 allowReadonly
00195 );
00196 d->storeResult();
00197
00198 if (d->res == SQLITE_OK && cancelled && !wasReadOnly && allowReadonly && isReadOnly()) {
00199
00200 if (KMessageBox::Continue !=
00201 askQuestion(
00202 i18n("Do you want to open file \"%1\" as read-only?")
00203 .arg(QDir::convertSeparators(data()->fileName()))
00204 + "\n\n"
00205 + i18n("The file is probably already open on this or another computer.") + " "
00206 + i18n("Could not gain exclusive access for writing the file."),
00207 KMessageBox::WarningContinueCancel, KMessageBox::Continue,
00208 KGuiItem(i18n("Open As Read-Only"), "fileopen"), KStdGuiItem::cancel(),
00209 "askBeforeOpeningFileReadOnly", KMessageBox::Notify, msgHandler ))
00210 {
00211 clearError();
00212 if (!drv_closeDatabase())
00213 return false;
00214 *cancelled = true;
00215 return false;
00216 }
00217 }
00218
00219 if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_READWRITE) {
00220 setError(ERR_ACCESS_RIGHTS,
00221 i18n("The file is probably already open on this or another computer.")+"\n\n"
00222 + i18n("Could not gain exclusive access for reading and writing the file.") + " "
00223 + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
00224 }
00225 else if (d->res == SQLITE_CANTOPEN_WITH_LOCKED_WRITE) {
00226 setError(ERR_ACCESS_RIGHTS,
00227 i18n("The file is probably already open on this or another computer.")+"\n\n"
00228 + i18n("Could not gain exclusive access for writing the file.") + " "
00229 + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
00230 }
00231 return d->res == SQLITE_OK;
00232 #endif
00233 }
00234
00235 bool SQLiteConnection::drv_closeDatabase()
00236 {
00237 if (!d->data)
00238 return false;
00239
00240 #ifdef SQLITE2
00241 sqlite_close(d->data);
00242 d->data = 0;
00243 return true;
00244 #else
00245 const int res = sqlite_close(d->data);
00246 if (SQLITE_OK == res) {
00247 d->data = 0;
00248 return true;
00249 }
00250 if (SQLITE_BUSY==res) {
00251 #if 0 //this is ANNOYING, needs fixing (by closing cursors or waiting)
00252 setError(ERR_CLOSE_FAILED, i18n("Could not close busy database."));
00253 #else
00254 return true;
00255 #endif
00256 }
00257 return false;
00258 #endif
00259 }
00260
00261 bool SQLiteConnection::drv_dropDatabase( const QString &dbName )
00262 {
00263 Q_UNUSED(dbName);
00264 const QString filename = data()->fileName();
00265 if (QFile(filename).exists() && !QDir().remove(filename)) {
00266 setError(ERR_ACCESS_RIGHTS, i18n("Could not remove file \"%1\".")
00267 .arg(QDir::convertSeparators(filename)) + " "
00268 + i18n("Check the file's permissions and whether it is already opened and locked by another application."));
00269 return false;
00270 }
00271 return true;
00272 }
00273
00274
00275 Cursor* SQLiteConnection::prepareQuery( const QString& statement, uint cursor_options )
00276 {
00277 return new SQLiteCursor( this, statement, cursor_options );
00278 }
00279
00280 Cursor* SQLiteConnection::prepareQuery( QuerySchema& query, uint cursor_options )
00281 {
00282 return new SQLiteCursor( this, query, cursor_options );
00283 }
00284
00285 bool SQLiteConnection::drv_executeSQL( const QString& statement )
00286 {
00287
00288
00289
00290 #ifdef SQLITE_UTF8
00291 d->temp_st = statement.utf8();
00292 #else
00293 d->temp_st = statement.local8Bit();
00294 #endif
00295
00296 #ifdef KEXI_DEBUG_GUI
00297 KexiUtils::addKexiDBDebug(QString("ExecuteSQL (SQLite): ")+statement);
00298 #endif
00299
00300 d->res = sqlite_exec(
00301 d->data,
00302 (const char*)d->temp_st,
00303 0,
00304 0,
00305 &d->errmsg_p );
00306 d->storeResult();
00307 #ifdef KEXI_DEBUG_GUI
00308 KexiUtils::addKexiDBDebug(d->res==SQLITE_OK ? " Success" : " Failure");
00309 #endif
00310 return d->res==SQLITE_OK;
00311 }
00312
00313 Q_ULLONG SQLiteConnection::drv_lastInsertRowID()
00314 {
00315 return (Q_ULLONG)sqlite_last_insert_rowid(d->data);
00316 }
00317
00318 int SQLiteConnection::serverResult()
00319 {
00320 return d->res==0 ? Connection::serverResult() : d->res;
00321 }
00322
00323 QString SQLiteConnection::serverResultName()
00324 {
00325 QString r =
00326 #ifdef SQLITE2
00327 QString::fromLatin1( sqlite_error_string(d->res) );
00328 #else //SQLITE3
00329 QString::null;
00330 #endif
00331 return r.isEmpty() ? Connection::serverResultName() : r;
00332 }
00333
00334 void SQLiteConnection::drv_clearServerResult()
00335 {
00336 if (!d)
00337 return;
00338 d->res = SQLITE_OK;
00339 #ifdef SQLITE2
00340 d->errmsg_p = 0;
00341 #else
00342
00343 #endif
00344 }
00345
00346 QString SQLiteConnection::serverErrorMsg()
00347 {
00348 return d->errmsg.isEmpty() ? Connection::serverErrorMsg() : d->errmsg;
00349 }
00350
00351 PreparedStatement::Ptr SQLiteConnection::prepareStatement(PreparedStatement::StatementType type,
00352 FieldList& fields)
00353 {
00354
00355 return new SQLitePreparedStatement(type, *d, fields);
00356
00357 }
00358
00359 bool SQLiteConnection::isReadOnly() const
00360 {
00361 #ifdef SQLITE2
00362 return Connection::isReadOnly();
00363 #else
00364 return d->data ? sqlite3_is_readonly(d->data) : false;
00365 #endif
00366 }
00367
00368 #ifdef SQLITE2
00369 bool SQLiteConnection::drv_alterTableName(TableSchema& tableSchema, const QString& newName, bool replace)
00370 {
00371 const QString oldTableName = tableSchema.name();
00372 const bool destTableExists = this->tableSchema( newName ) != 0;
00373
00374
00375 if (destTableExists) {
00376 if (!replace)
00377 return false;
00378 if (!drv_dropTable( newName ))
00379 return false;
00380 }
00381
00382
00383
00384 tableSchema.setName(newName);
00385
00386
00387 #define drv_alterTableName_ERR \
00388 tableSchema.setName(oldTableName) //restore old name
00389
00390 if (!drv_createTable( tableSchema )) {
00391 drv_alterTableName_ERR;
00392 return false;
00393 }
00394
00395
00396
00397
00398 if (!executeSQL(QString::fromLatin1("INSERT INTO %1 SELECT * FROM %2")
00399 .arg(escapeIdentifier(tableSchema.name())).arg(escapeIdentifier(oldTableName))))
00400 {
00401 drv_alterTableName_ERR;
00402 return false;
00403 }
00404
00405
00406 if (!drv_dropTable( oldTableName )) {
00407 drv_alterTableName_ERR;
00408 return false;
00409 }
00410 return true;
00411 }
00412 #endif
00413
00414 #include "sqliteconnection.moc"