Deleting local sqlite-file not possible: Access denied



  • Dear community,
    this code opens a local sqlite 3 file as SQLite Databse in Qt, and checks the version of that file (included in a table in the database. My System is Qt5.8 with QtCreator in the newest version and Windows 10. I tried both MinGW and Visual Studio Compiler, but always get the same error. What I want to do is delete that sqlitefile (in order to replace it) if it has an older version than the application. Opening the database and retrieving the version works fine, but I can't figure out why I can't delete the file. It always says Access denied, when I try to delete it.

    The weird thing is that it even says access denied, when I try to delete the file before I open the database. This even happens when I restart the computer and then try to delete the file before I open the database (in Qt, as user it is no problem for me to delete the file). The only case when the file gets deleted is if i delete it myself, replace it and then delete the file by Qt before I open the database.

    But once I have opened the database I can't delete it any longer (using Qt), even when I restart the pc. Can you maybe figure out what I am doing wrong?

        bool copyDatabase = true;
        QFile f(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/database.sqlite");
        if(f.exists()) {
            {
                QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");//not dbConnection
                db.setDatabaseName(f.fileName()); //if the database file doesn't exist yet, it will create it
                if (!db.open()){
                    qCritical().noquote() << db.lastError().text();
                } else {
                    qDebug() << "Successfully connected to database.";
                }
                QSqlQuery query;
                if(!query.exec("SELECT * FROM version")) qWarning() << "Error retrieving version from existing database.";
                query.first();
                if(query.isValid()){
                    QVector<int> app_version = {APP_VERSION_NR};
                    QVector<int> db_version(3);
                    for(int i = 0; i < 3; i++) db_version[i] = query.value(i).toInt();
                    copyDatabase = app_version != db_version;
                    qDebug() << (copyDatabase ? "The database- and app versions are not equal." : "The database- and app versions are equal.") <<
                        "Database-version:" << db_version;
                }
            }
            QSqlDatabase::removeDatabase("qt_sql_default_connection");
            qDebug() << QSqlDatabase::connectionNames();
        }
        qDebug().noquote() << (f.remove() ? "The database file was successfully removed" : QString("The file could not be removed ") + f.errorString());
    

    The console output this produces is

    Successfully connected to database.
    The database- and app versions not equal. Database-version: QVector(1, 0, 2)
    ()
    The file could not be removed Access denied
    

    Out of this output we can see that the database-connection works, and that the connection is successfully removed. () is the empty QStringList of database-connections printed in the 4th last line. So the connection is successsfully removed, and all the querys and database connections are definitely out of scope. Still Qt doesn't let me delete the file, it says Access denied. Why? What else do i need to do?

    Appreciate your help :)


  • Lifetime Qt Champion

    Hi,

    Are you sure you are opening the database in the AppDataLocation folder ?



  • @SGaist Yes, the file is opened in AppData. Even though it is not visible in the output, I check in the first if-statement if the file exists, before I do anything more. And it definitely is that file, because if I delete it and replace it, Qt may delete it before I open the database for the first time. But not after i opened it.

    Greetings



  • @randsfjorden
    Is the file still open? Windows can't delete files that are still in use by any application

    Edit
    As I can see you add a default connection without a connection name buto try to remove a named connection
    See http://doc.qt.io/qt-5/qsqldatabase.html#removeDatabase how to remove a default connection



  • @the_ What you say is actually true, and now i replaced the line QSqlDatabase::removeDatabase("qt_sql_default_connection"); with QSqlDatabase::removeDatabase(QSqlDatabase::database().connectionName()); At least I get better error messages now :) QSqlDatabase::database().connectionName() returns exactly the same string as I had inserted, but this way is much safer.

    It still doesn't work, but now I know at least that there must be something wrong with the way I connect to the database. Trying to remove the connection now, I get the following error: QSqlDatabasePrivate::removeDatabase: connection 'qt_sql_default_connection' is still in use, all queries will cease to work. This is the error one is usually supposed to get if the database-connections and the queries are not out of scope. But when I try to remove the connection, they are out of scope!


  • Lifetime Qt Champion

    How many database connection do you have ?

    As for the error message, do you have any QSqlDatabase member variable somewhere ?



  • No, I have no more QSqlDatabase-connections, and no more QSqlDatabase memberes either. I never open more than this single connection.


  • Lifetime Qt Champion

    I'd close the database connection before removing it.



  • I tested it, and closing the connection before makes no difference, because it is closed automatically when it goes out of scope (this is at least what it sais in the documentation).

    I have no more code than this (and no other connections), because i created a test-project in order to solve the problem, which doesn't contain anything else.


  • Lifetime Qt Champion

    Can you share the code of your minimal sample project ?



  • I now found the error. It had nothing to do with the database itself.

    #include <QGuiApplication>
    #include <QQmlApplicationEngine>
    #include <QFile>
    #include <QDir>
    #include <QDebug>
    #include <QStandardPaths>
    
    int main(int argc, char *argv[])
    {
        QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
        QGuiApplication app(argc, argv);
    
        QQmlApplicationEngine engine;
        engine.load(QUrl(QLatin1String("qrc:/main.qml")));
        app.setApplicationName("sample");
        app.setOrganizationName("developer");
    
        QFileInfo databaseFile(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + "/database.txt");
        QFile f(databaseFile.absoluteFilePath());
        if(QDir().mkpath(databaseFile.absolutePath()));
    
        //the error is caused by the way I copied the database-file, and had nothing to do with the database-connection itself.
    
        //copying file from FileSystem
        if(!QFile::copy("D:/Dokumente/Qt/Workspace/test/" + databaseFile.fileName(), databaseFile.absoluteFilePath()))
            qWarning() << "Could not copy current version of database - check file permissions.";
        qDebug().noquote() << (f.remove() ? "Successfully deleted file" : "Could not delete old file." + f.errorString());
        //when I create this way (copy the local file to the new destination), everything works as you would expect.
    
        //The file is deleted, so the environment is "clean" again for the way I copied the file that produced the Access-denied error.
    
        //copying file from Ressources
        if(!QFile::copy(":/" + databaseFile.fileName(), databaseFile.absoluteFilePath()))
            qWarning() << "Could not copy current version of database - check file permissions.";
        qDebug().noquote() << (f.remove() ? "Successfully deleted file" : "Could not delete old file. " + f.errorString());
        //This does not work. The file is successfully copied, but after that it is imossible to delete the file through
        //Qt, even when the application is restarted or the whole Operating system is restarted it is impossible to delete the file.
        //The only way to resolve this is that I delete the file again myself. I have no clue why copying the file from the ressources creates that error.
    }
    

    This is the simple code producing the access-denied error. The file type doesn't matter - as you can see I replaced the .sqlite file with a .txt-file.

    The code produces the following output:

    Successfully deleted file
    Could not delete old file. Access denied
    

    Notice that copying works both times, because copying just prints a message if it fails.
    The local file I use in the case when it works to delete it is the ressource file in my local filesystem. But why is it a problem to copy a file from the compiled-in ressources?


  • Qt Champions 2016

    Hi
    what os are u on ?
    Tried (hopefully) the same on win 10 and could not reproduce it.
    I assume that u are in fact logged in as lukas on your test system.



  • The Test System is Windows 10, and I am indeed logged on as Lukas (who is an Administrator).


  • Qt Champions 2016

    @randsfjorden
    Hmm. i copy a random file (from res) to a writable Location but i can always
    remove it.
    I wonder if it has to be a db or any file would do it?



  • In my test case the file type doesn't matter - as you can see I now used a txt-file to produce the error.

    The output and behavior is the same no matter which compiler I use (MinGW or MSVC2015).


  • Qt Champions 2016

    Hi
    is there anyway u could upload your complete sample for me ? ( google drive/ dropbox)
    I feel i might do something wrong in order to reproduce it.
    I have a feeling something is wrong if u cant even delete it after a reboot as any
    locks will be removed so i wonder if Qt or local to ur system :)



  • Here I uploaded the zipped project https://1drv.ms/u/s!ApYSo539xqGngcF-QFMUiHaL6sQVdQ


  • Qt Champions 2016

    @randsfjorden

    Hi
    It seems that the "developer" folder that is created
    is read only and hence the file is also made readonly and then remove wont delete it.
    alt text

    If i uncheck readonly from file. f.remove() works.



  • Thank you soooo much for your help and for your answer!

    If I call f.setPermissions(QFile::ReadOther|QFile::WriteOther); before QFile::remove();, it removes the ReadOnly flag, and I may delete the file. I'm sorry that I didn't notice myself, and that it took you all so much time and 18 posts.

    But it actually makes sense. Of course the compiled-in ressource file has the ReadOnly-flag set - nobody is supposed to change a compiled-in ressource, and it is not possible either. But I was simply not aware that the ReadOnly-flag also would be set for a file that was copied from ressources. Maybe this is something you could include in the documentation about QRessources? Would have helped me a lot :)


  • Qt Champions 2016

    @randsfjorden
    Well it was a tricky one as we all thought it was related to the db. :)

    Funny enough , its very much same situation as in old times when you copy files from a cdrom to some folder.
    so maybe its not even really Qt related but an OS thing. I wonder if same would happen in linux.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.