1

I'm doing an insertion query using SQLite3 with Spatialite on Qt and sometimes it just fails returning random syntax errors. If I run the queries on SpatialiteGUI it never fails.

I'm using SQLite3 version 3.27.2.

The method that builds and runs the query:

bool DatabaseManager::insertPolygons(QList<QList<QGeoCoordinate>> polygons, int workId) 
{
    sqlite3_stmt *dbStatement = nullptr;

    QString strQuery = "INSERT INTO \"WORK_" + QString::number(workId) + "\" (Geometry) VALUES ";
    bool inserted = false;

    for(int i = 0; i < polygons.size(); i++) {
        strQuery += "(GeomFromText('POLYGON((";

        foreach (QGeoCoordinate coordinate, polygons[i]) {
            strQuery += QString::number(coordinate.longitude(), 'f', 10) + " " +
                        QString::number(coordinate.latitude(), 'f', 10)  + ",";
        }

        strQuery = strQuery.left(strQuery.size() - 1) + "))', 4326)),";
    }

    strQuery = strQuery.left(strQuery.size() - 1) + ";";

    char *query = strQuery.toLatin1().data();

    int status = sqlite3_prepare_v2(database, query, strQuery.toLatin1().size(), &dbStatement, 0);

    if(status == SQLITE_OK) {
        int status = 0;

        status = sqlite3_step(dbStatement);

        if(status == SQLITE_DONE)
            inserted = true;
    }else
        qDebug().noquote() << "status:" << status << "error:" << sqlite3_errmsg(database);

    sqlite3_finalize(dbStatement);

    return inserted; 
}

Some queries examples:

INSERT INTO "WORK_264" (Geometry) VALUES 
(GeomFromText('POLYGON((-52.3855298461 -28.2283621371,-52.3855220463 -28.2283563298,-52.3855103297 -28.2283685464,-52.3855181295 -28.2283743537,-52.3855298461 -28.2283621371))', 4326)),
(GeomFromText('POLYGON((-52.3855454459 -28.2283737516,-52.3855376460 -28.2283679443,-52.3855259294 -28.2283801609,-52.3855337292 -28.2283859682,-52.3855454459 -28.2283737516))', 4326)),
(GeomFromText('POLYGON((-52.3855610456 -28.2283853661,-52.3855532457 -28.2283795588,-52.3855415291 -28.2283917755,-52.3855493289 -28.2283975828,-52.3855610456 -28.2283853661))', 4326)),
(GeomFromText('POLYGON((-52.3855766453 -28.2283969805,-52.3855688455 -28.2283911733,-52.3855571288 -28.2284033900,-52.3855649286 -28.2284091973,-52.3855766453 -28.2283969805))', 4326));

INSERT INTO "WORK_264" (Geometry) VALUES 
(GeomFromText('POLYGON((-52.3868293314 -28.2269741900,-52.3868371280 -28.2269800006,-52.3868488522 -28.2269677737,-52.3868410531 -28.2269619658,-52.3868293314 -28.2269741900))', 4326)),
(GeomFromText('POLYGON((-52.3868137382 -28.2269625689,-52.3868215348 -28.2269683795,-52.3868332540 -28.2269561579,-52.3868254549 -28.2269503500,-52.3868137382 -28.2269625689))', 4326)),
(GeomFromText('POLYGON((-52.3867981450 -28.2269509478,-52.3868059416 -28.2269567584,-52.3868176557 -28.2269445420,-52.3868098566 -28.2269387341,-52.3867981450 -28.2269509478))', 4326)),
(GeomFromText('POLYGON((-52.3867825518 -28.2269393267,-52.3867903484 -28.2269451373,-52.3868020575 -28.2269329262,-52.3867942584 -28.2269271183,-52.3867825518 -28.2269393267))', 4326));

Output:

status: 1 error: near "database": syntax error

status: 1 error: near "�": syntax error
0

2 Answers 2

1

strQuery.toLatin1() is a temporary value, and .data() grabs a pointer within that value. This is effectively a dangling pointer.

Add an intermediate holding variable: (and use UTF8 instead of Latin1 while you're at it)

auto queryBA = strQuery.toUtf8();
int status = sqlite3_prepare_v2(database, queryBA.data(), queryBA.size(), &dbStatement, 0);
Sign up to request clarification or add additional context in comments.

Comments

1

To solve this mystery all we have to do is double-check what's going on by reading Qt's documentation.

char *query = strQuery.toLatin1().data();

According to Qt's documentation, QString's toLatin1() method returns a QByteArray object.

Next, we determine that QByteArray's data() method returns a "pointer [that] remains valid as long as the byte array isn't reallocated or destroyed".

Well, now, the problem is clear. toLatin1() returns a temporary QByteArray object that, as per C++ usual rules governing temporary objects, gets destroyed at the end of the expression. Before that happens data() returns a pointer to its innards, which gets saved in query.

But that pointer immediately becomes a pointer to deallocated memory, and any further use of this pointer results in undefined behavior.

The simplest fix here is to take toLatin1()'s object, and save it as a local variable, that only gets destroyed after its data() is no longer needed. Something like:

QByteArray strarray = strQuery.toLatin1();

char *query=strarray.data();

1 Comment

Giving the answer to Botje because he replied first, but thanks for the explanation. Have a good one!!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.