Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

"undefined reference to `sqlite3_key'" - using QtCipherSqlitePlugin



  • Hi,
    I am trying to use the sqlite backup API using QtCipherSqlitePlugin, which itself is based on wxsqlite. I recieve a "Not a database"-error (#26), probably because I have to set the password for the .sqlite-file. It seems that theoretically this should work (see "SQLite3 backup API" at the bottom of this page).

    I try to do this with sqlite3_key mentioned here.
    Unfortunately this doesn't compile, throwing "undefined reference to `sqlite3_key'".

    I have added DEFINES += SQLITE_HAS_CODEC and #define [the same] at several places in my code and the actual plugin works, I can work on an encrypted db on disk or in :memory:. I just need RAM speed for the work AND I have to be able to save the db to disk (also encrypted).

    What am I missing? (Win10/64b, Qt5.11.1, MinGW)

    Or, taking a step backwards, does anybody know a different tool which makes sqlite encryption possible on Windows and Android?


  • Lifetime Qt Champion

    Hi,

    Can you show exactly how you are trying to use the backup API and how you are setting up your encrypted database ?



  • Hi,
    the setup of the db is - shortened -:

    // databaseType is "SQLITECIPHER"
    this->database = QSqlDatabase::addDatabase(databaseType, connectionName);
    this->database.setHostName(hostname);
    this->database.setDatabaseName(databasename);
    this->database.setPassword(password);
    this->database.open();
    

    See code below for the actual saving (and opening, when save == false). It works well (fast and reliable) with an unencrypted database.

    bool SqliteBackupProcessor::sqliteDBMemFile(bool save, QString fileName) {
        bool state = false;
        QVariant v = this->database->getDatabase().driver()->handle();
        if ( v.isValid() && qstrcmp(v.typeName(), "sqlite3*") == 0 ) {
            // v.data() returns a pointer to the handle
            sqlite3 *handle = *static_cast<sqlite3 **>(v.data());
            if ( handle != 0 ) { // check that it is not NULL
                sqlite3 *pInMemory = handle;
                QByteArray array = QString(this->destination + "/" + fileName).toLocal8Bit();
                const char *zFilename = array.data();
    //            const char *zFilename = array;
                int rc;                   /* Function return code */
                sqlite3 *pFile;           /* Database connection opened on zFilename */
                /* Open the database file identified by zFilename. Exit early if this fails
                ** for any reason. */
                rc = sqlite3_open( zFilename, &pFile );
    ////////////////////////////////////////////////////////////
    /// not working:
                sqlite3_key(pFile, "test", strlen("test"));
    ////////////////////////////////////////////////////////////
                if ( rc == SQLITE_OK ) {
                    sqlite3_backup *pBackup;  /* Backup object used to copy data */
                    sqlite3 *pTo;             /* Database to copy to (pFile or pInMemory) */
                    sqlite3 *pFrom;           /* Database to copy from (pFile or pInMemory) */
                    /* If this is a 'load' operation (isSave==0), then data is copied
                    ** from the database file just opened to database pInMemory.
                    ** Otherwise, if this is a 'save' operation (isSave==1), then data
                    ** is copied from pInMemory to pFile.  Set the variables pFrom and
                    ** pTo accordingly. */
                    pFrom = ( save ? pInMemory : pFile);
                    pTo   = ( save ? pFile     : pInMemory);
                    /* Set up the backup procedure to copy from the "main" database of
                    ** connection pFile to the main database of connection pInMemory.
                    ** If something goes wrong, pBackup will be set to NULL and an error
                    ** code and  message left in connection pTo.
                    **
                    ** If the backup object is successfully created, call backup_step()
                    ** to copy data from pFile to pInMemory. Then call backup_finish()
                    ** to release resources associated with the pBackup object.  If an
                    ** error occurred, then  an error code and message will be left in
                    ** connection pTo. If no error occurred, then the error code belonging
                    ** to pTo is set to SQLITE_OK.
                    */
                    pBackup = sqlite3_backup_init(pTo, "main", pFrom, "main");
                    do {
                        if ( pBackup ) {
                            (void)sqlite3_backup_step(pBackup, 5);
                            (void)sqlite3_backup_finish(pBackup);
                        }
                        rc = sqlite3_errcode(pTo);
                        if( rc==SQLITE_OK || rc==SQLITE_BUSY || rc==SQLITE_LOCKED ){
                          sqlite3_sleep(250);
                        }
                    } while ( rc==SQLITE_OK || rc==SQLITE_BUSY || rc==SQLITE_LOCKED );
                }
                /* Close the database connection opened on database file zFilename
                ** and return the result of this function. */
                (void)sqlite3_close(pFile);
                if ( rc == SQLITE_OK ) {
                    state = true;
                }
            }
        }
        return state;
    }
    

  • Lifetime Qt Champion

    Silly question but: are you linking your project against SQLite ?



  • Not silly at all. I feel rather silly because I am not sure about the answer. I guess so, yes. At least I find "-DQT_SQL_LIB" in my compile output and basic functionality is working:

    g++ -c -fno-keep-inline-dllexport -Wall -Wextra -pedantic -Wpointer-arith -Wcast-align -Wunreachable-code -isystem 
    C:/Qt/5.11.1/mingw53_32/include -Wno-unused-function -g -std=gnu++1y -Wall -W -Wextra -fexceptions -mthreads -DUNICODE -D_UNICODE -DWIN32 -DCUTE_ENTITY_MANAGER_LIBRARY_SHARED -DQT_QML_DEBUG -DQT_QUICK_LIB -DQT_SVG_LIB -DQT_CHARTS_LIB -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_QML_LIB -DQT_NETWORK_LIB -DQT_SQL_LIB -DQT_CORE_LIB -DQT_NEEDS_QMAIN -I../ClassInTouch2 -I. -I../ClassInTouch2/libs/entitymanager/src -I../ClassInTouch2/libs/QtQmlTricks/SuperMacros -I../ClassInTouch2/libs/QtQmlTricks/SmartDataModels -IC:/Qt/5.11.1/mingw53_32/include -IC:/Qt/5.11.1/mingw53_32/include/QtQuick -IC:/Qt/5.11.1/mingw53_32/include/QtSvg -IC:/Qt/5.11.1/mingw53_32/include/QtCharts -IC:/Qt/5.11.1/mingw53_32/include/QtWidgets -IC:/Qt/5.11.1/mingw53_32/include/QtGui -IC:/Qt/5.11.1/mingw53_32/include/QtANGLE -IC:/Qt/5.11.1/mingw53_32/include/QtQml -IC:/Qt/5.11.1/mingw53_32/include/QtNetwork -IC:/Qt/5.11.1/mingw53_32/include/QtSql -IC:/Qt/5.11.1/mingw53_32/include/QtCore -Idebug -IC:/Qt/5.11.1/mingw53_32/mkspecs/win32-g++  -o deb
    

    Is that a yes?
    I have added the svg module as well:

    QT += qml quick sql svg charts
    

    [sorry for not answering for a long time, I have been travelling and couldn't sensibly work on this part of the program]


  • Lifetime Qt Champion

    That's for the module itself. It provides the a SQLite plugin but your application won't get linked to it unless you build Qt to have that plugin builtin. Therefore, you'll have to link your application directly against the SQLite library.


Log in to reply