Segfault during custom collation creation sqlite using qt

If you have installed Qt using the online installer then it has been compiled not using the system sqlite so you have to download the sqlite amalgation (the version of sqlite depends on the version that was used to compile Qt which you can get using SELECT sqlite_version(), in Qt 5.15 you get 3.31.1 so you have to download https://www.sqlite.org/2020/sqlite-amalgamation-3310100.zip. You can also find out this information by checking the qt_attribution.json file in the source code.

├── 3rdParty
│   ├── sqlite
│   │   ├── shell.c
│   │   ├── sqlite3.c
│   │   ├── sqlite3ext.h
│   │   └── sqlite3.h
│   └── sqlite.pri
├── 64591348.pro
└── main.cpp

*.pro

QT -= gui
QT += sql
CONFIG += c++11 console
CONFIG -= app_bundle


SOURCES += main.cpp

include(3rdParty/sqlite.pri)

sqlite.pri

INCLUDEPATH += $$PWD/sqlite

SOURCES += $$PWD/sqlite/sqlite3.c
LIBS += -ldl

main.cpp

#include <QSqlDatabase>
#include <QSqlDriver>
#include <QSqlError>
#include <QSqlQuery>
#include <QVariant>
#include <QDebug>

#include <sqlite3.h>

int localeCompare(void *, int len1, const void *data1, int len2, const void* data2)
{
    auto qstr1 = QString::fromUtf8(reinterpret_cast<const char*>(data1), len1 * 4);
    auto qstr2 = QString::fromUtf8(reinterpret_cast<const char*>(data2), len2 * 4);

    int end = 0;
    while (qstr1[end] != '\0') {end++;}
    qstr1.truncate(end + 1);

    end = 0;
    while (qstr2[end] != '\0') {end++;}
    qstr2.truncate(end + 1);

    return QString::compare(qstr1, qstr2, Qt::CaseInsensitive);
}

bool create_collate(QSqlDatabase db)
{
    QVariant v = db.driver()->handle();
    if (!v.isValid() || qstrcmp(v.typeName(), "sqlite3*") != 0)
        return false;

    sqlite3* sql_db = *static_cast<sqlite3* const*>(v.data());
    if (!sql_db)
        return false;

    sqlite3_initialize();
    return sqlite3_create_collation(sql_db, "NOACCENTS", SQLITE_UTF8, NULL, &localeCompare) == SQLITE_OK;
}
int main(int argc, char *argv[])
{
    Q_UNUSED(argc)
    Q_UNUSED(argv)
    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(":memory:");
    if(!db.open())
        return -1;
    QSqlQuery q;
    if(!q.exec("SELECT sqlite_version()")){
        qDebug() << q.lastError().text();
        return -1;
    }
    if(q.first()){
        qDebug() << q.value(0).toString();
    }
    if(!create_collate(db))
        return -1;
    if(!q.exec("CREATE TABLE test(x)")){
        qDebug() << q.lastError().text();
        return -1;
    }
    q.prepare("INSERT into test(x) values (?)");
    for(const QString & word: {"z", "a", "p"}){
        q.addBindValue(word);
        if(!q.exec()){
            qDebug() << q.lastError().text();
            return -1;
        }
    }
    if(!q.exec("SELECT x FROM test ORDER BY x COLLATE NOACCENTS")){
        qDebug() << q.lastError().text();
        return -1;
    }
    while (q.next()) {
        qDebug() << q.value(0).toString();
    }

    return 0;
}

Output:

"3.31.1"
"a"
"p"
"z"

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top