无法在qSqlite中加载Spatialite扩展(QT 5.9)

时间:2017-06-08 06:09:43

标签: c++ qt sqlite qt5 spatialite

我正在尝试在qSqlite(Qt 5.9)中加载Spatialite作为扩展,我在使用Qt4.8之前已经完成了,但是我在QT5.9中失败了。 我通过删除" SQLITE_OMIT_LOAD_EXTENSION"来更改sqlite.pri,并通过删除" #define SQLITE_OMIT_LOAD_EXTENSION 1"并添加"来对sqlite.c做了一些更改。 #define SQLITE_ENABLE_LOAD_EXTENSION 1&#34 ;. 我还将以下行添加到openDatabase(....)

#if defined(SQLITE_ENABLE_LOAD_EXTENSION)
| SQLITE_LoadExtension|SQLITE_LoadExtFunc
#endif

现在" requet.setQuery(" SELECT load_extension(' spatialite')",dbProject);"功能被识别,但我得到了这样的信息: 错误"找不到指定的过程。\ r \ n无法获取行" 如果我查看MSVC14中的调试输出,我可以看到已经加载了spatialite.dll及其所有依赖项。

注意:我使用我的Spatialite以及从网站下载的mod_spatialite进行了测试。

有关此问题的任何想法? 提前谢谢。

2 个答案:

答案 0 :(得分:3)

根据示例here我在sqlite中启用了spatialite,该函数启用该模块。为此,您必须链接sqlite3库。

所做的修改是:

  • "SELECT load_extension('libspatialite.so')"更改为"SELECT load_extension('mod_spatialite')"

  • "SELECT InitSpatialMetadata()"更改为"SELECT InitSpatialMetadata(1)"

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

int enable_spatialite(QSqlDatabase db){
    QVariant v = db.driver()->handle();
    if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*")==0)
    {
        sqlite3_initialize();
        sqlite3 *db_handle = *static_cast<sqlite3 **>(v.data());

        if (db_handle != 0) {
            sqlite3_enable_load_extension(db_handle, 1);

            QSqlQuery query;

            query.exec("SELECT load_extension('mod_spatialite')");
            if (query.lastError() .isValid())
            {
                qDebug() << "Error: cannot load the Spatialite extension (" << query.lastError().text()<<")";
                return 0;
            }

            qDebug()<<"**** SpatiaLite loaded as an extension ***";

            query.exec("SELECT InitSpatialMetadata(1)");
            if (query.lastError() .isValid())
            {
                qDebug() << "Error: cannot load the Spatialite extension (" << query.lastError().text()<<")";
                return 0;
            }
            qDebug()<<"**** InitSpatialMetadata successful ***";

            return 1;
        }
    }
    return 0;
}

示例:

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    QSqlDatabase db =  QSqlDatabase::addDatabase("QSQLITE");

    db.setDatabaseName("memory.db");
    if (!db.open()) {
        qDebug()<<"not open";
    }

    qDebug()<<enable_spatialite(db);

    QSqlQuery query;

    qDebug()<<query.exec("CREATE TABLE test_geom (id INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT, name TEXT NOT NULL, measured_value DOUBLE NOT NULL);");
    qDebug()<<query.exec("SELECT AddGeometryColumn('test_geom', 'the_geom', 4326, 'POINT', 'XY');");



    for(int i=0; i< 10; i++){
        QString q = QString("INSERT INTO test_geom(id, name, measured_value, the_geom) VALUES (%1,'point %2', %3, GeomFromText('POINT(1.01 2.02)', 4326))")
                .arg("NULL").arg(i).arg(i);
        query.prepare(q);
        qDebug()<< i<<query.exec();
    }

    qDebug()<<query.exec("SELECT id, name, measured_value,  AsText(the_geom), ST_GeometryType(the_geom), ST_Srid(the_geom) FROM test_geom");


    while (query.next()) {
        QString str;
        for(int i=0; i < query.record().count(); i++)
            str += query.value(i).toString() + " ";
        qDebug()<<str;
    }
    return a.exec();
}

输出:

**** SpatiaLite loaded as an extension ***
**** InitSpatialMetadata successful ***
1
true
true
0 true
1 true
2 true
3 true
4 true
5 true
6 true
7 true
8 true
9 true
true
"1 point 0 0 POINT(1.01 2.02) POINT 4326 "
"2 point 1 1 POINT(1.01 2.02) POINT 4326 "
"3 point 2 2 POINT(1.01 2.02) POINT 4326 "
"4 point 3 3 POINT(1.01 2.02) POINT 4326 "
"5 point 4 4 POINT(1.01 2.02) POINT 4326 "
"6 point 5 5 POINT(1.01 2.02) POINT 4326 "
"7 point 6 6 POINT(1.01 2.02) POINT 4326 "
"8 point 7 7 POINT(1.01 2.02) POINT 4326 "
"9 point 8 8 POINT(1.01 2.02) POINT 4326 "
"10 point 9 9 POINT(1.01 2.02) POINT 4326 "

可以找到完整的示例here

此代码已在linux Arch Linux 4.11.3-1-ARCH,Qt 5.8

上测试过

答案 1 :(得分:2)

感谢eyllanesc,由于您的解释和建议,我找到了解决方案。

问题在于我编译的库(我还不知道为什么?),还有我下载的mod_spatialite。当我们在visual studio中使用它时,最后一个需要替换diag(p)[1],因为它会导致崩溃。

我的问题在这里,我使用的那个不是好的,并且导致了libstdc++_64-6.dll,所以我下载了The specified procedure could not be found并且我使用了x86_64-5.3.0-release-win32-seh-rt_v4-rev0(我更改了)使用libstdc++-6.dll的{​​{1}})名称。我还用我之前编译的另一个更改了libstdc++_64-6.dll

然后我使用了以下解决方案之一:

解决方案1: 我之前使用过代码进行修改,因为libgcc_s_seh-1.dll导致了崩溃,我也通过参数发送了db,因为它不像以前的代码那样工作。

所以我现在的工作代码是:

libxml2-2.dll

还有一件重要的事情,就是我重新编译了qsqlite驱动程序以删除SQLITE_OMIT_LOAD_EXTENSION

解决方案2 :(直接解决方案)

打开&#34; Qt5.9.0 \ 5.9 \ Src \ qtbase \ src \ 3rdparty \ sqlite \&#34;文件夹并更改sqlite3.c如下:

  1. 评论或删除ret = sqlite3_exec (db_handle, sql, NULL, NULL, &err_msg);

  2. 添加:

  3. #include <QtCore/QCoreApplication>
    #include <QtSql/QtSql>
    #include "sqlite3.h"
    
    int enable_spatialite(QSqlDatabase db) {
        QVariant v = db.driver()->handle();
        if (v.isValid() && qstrcmp(v.typeName(), "sqlite3*") == 0)
        {
            sqlite3_initialize();
            sqlite3 *db_handle = *static_cast<sqlite3 **>(v.data());
    
            if (db_handle != 0) {
    
                sqlite3_enable_load_extension(db_handle, 1);
    
                QSqlQueryModel sql;
                sql.setQuery("SELECT load_extension('mod_spatialite')", db);
                if (sql.lastError().isValid())
                {
                    qDebug() << "Error: cannot load the Spatialite extension (" << sql.lastError().text()<<")";
                    return 0;
                }
                else    return 1;
            }
        }
        return 0;
    }
    
    int main(int argc, char *argv[])
    {
        QCoreApplication a(argc, argv);
    
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "Project");
        db.setDatabaseName("dbTest.db");
        if (!db.open())
        {
            qDebug()<<"Critical"<< "Impossible to intialize the database !\n" + db.lastError().text();
            return 0;
        }
        qDebug()<<enable_spatialite(db);
    
        //just a test
        QSqlQueryModel sql;
        sql.setQuery("SELECT HEX(GeomFromText('POINT(10 20)'));", db);
        qDebug() << sql.index(0, 0).data().toString();
    
        return a.exec();
    }
    
    1. 转到#define SQLITE_OMIT_LOAD_EXTENSION 1功能并将#ifndef SQLITE_ENABLE_LOAD_EXTENSION #define SQLITE_ENABLE_LOAD_EXTENSION 1 #endif 添加到static int openDatabase( const char *zFilename,sqlite3 **ppDb, unsigned int flags, const char *zVfs),如下所示:
    2. | SQLITE_LoadExtFunc
      1. 使用编译器(在我的例子中为nmake)在Qt5.9.0 \ 5.9 \ Src \ qtbase \ src \ plugins \ sqldrivers \ sqlite \ sqlite.pro

      2. 中再次编译插件
      3. 调用以下代码加载您的spaceite:

      4. SQLITE_ENABLE_LOAD_EXTENSION