【问题标题】:Segfault during custom collation creation sqlite using qt使用 qt 自定义排序规则创建 sqlite 期间的段错误
【发布时间】:2021-02-11 21:51:23
【问题描述】:

我正在尝试使用 sqlite 将自定义整理功能添加到 qt 项目中。 我遇到了一个我不理解的段错误,因此无法修复。

它来自以下代码,在 sqlite3_create_collat​​ion sql 函数中。

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

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

    sqlite3_initialize();
--> return sqlite3_create_collation(sql_db, "NOACCENTS", SQLITE_UTF8, NULL, &localeCompare); <--
}

segv 在到达这个特定函数时发生,在突出显示的行上:

static HashElem *findElementWithHash(
  const Hash *pH,     /* The pH to be searched */
  const char *pKey,   /* The key we are searching for */
  unsigned int *pHash /* Write the hash value here */
){
  HashElem *elem;                /* Used to loop thru the element list */
  unsigned int count;            /* Number of elements left to test */
  unsigned int h;                /* The computed hash */
  static HashElem nullElement = { 0, 0, 0, 0 };

  if( pH->ht ){   /*OPTIMIZATION-IF-TRUE*/
    struct _ht *pEntry;
    h = strHash(pKey) % pH->htsize;
    pEntry = &pH->ht[h];
--> elem = pEntry->chain; <--
    count = pEntry->count;
  }else{
    h = 0;
    elem = pH->first;
    count = pH->count;
  }
  if( pHash ) *pHash = h;
  while( count-- ){
    assert( elem!=0 );
    if( sqlite3StrICmp(elem->pKey,pKey)==0 ){ 
      return elem;
    }
    elem = elem->next;
  }
  return &nullElement;
}

sqlite -version的输出是3.32.3,和qt使用的版本一致,也是3.32.3。

编辑:

地区比较:

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(BkString::removeAccents(qstr1), BkString::removeAccents(qstr2), Qt::CaseInsensitive);
}

Qt 已通过在线安装程序安装完毕。

对应的.pro:

QT += core sql quick qml
QT -= gui

TEMPLATE = lib
CONFIG += unversioned_libname unversioned_soname # do not generate the symbolic link.

!android {
    LIBS += -lsqlite3 -ldl
}
TARGET = bkdatabase-core

INCLUDEPATH += ./src

SOURCES += ...
HEADERS += ...

一个最小的例子是:

#include <sqlite3.h>
#include <QSqlDatabase>

int main(void)
{
   QSqlDatabase db("QSQLITE");
   db.setDataBaseName("My_db");

   if (db.open())
      create_collate(&db);

   return 0;
}

【问题讨论】:

    标签: c++ sqlite qt


    【解决方案1】:

    如果您使用在线安装程序安装了 Qt,那么它不是使用系统 sqlite 编译的,因此您必须下载 sqlite 合并(sqlite 的版本取决于用于编译 Qt 的版本,您可以使用SELECT sqlite_version(),在 Qt 5.15 中你会得到 3.31.1,所以你必须下载 https://www.sqlite.org/2020/sqlite-amalgamation-3310100.zip。你也可以通过查看源代码中的 qt_attribution.json 文件来找到这些信息。

    ├── 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
    

    ma​​in.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;
    }
    

    输出:

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

    【讨论】:

    • 就是这样,我检查sqlite版本的方式错误,感谢提示和帮助!
    猜你喜欢
    • 2011-05-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多