Случайная синтаксическая ошибка в запросе вставки SQLite3

#c #sqlite #qt #syntax-error #spatialite

Вопрос:

Я выполняю запрос на вставку, используя SQLite3 с Spatialite на Qt, и иногда он просто не возвращает случайные синтаксические ошибки. Если я запускаю запросы в SpatialiteGUI, он никогда не завершается сбоем.

Я использую SQLite3 версии 3.27.2.

Метод, который создает и выполняет запрос:

 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(), amp;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; 
}
 

Некоторые примеры запросов:

 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));
 

Вывод:

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

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

Ответ №1:

strQuery.toLatin1() является временным значением и .data() захватывает указатель внутри этого значения. Фактически это висячий указатель.

Добавьте промежуточную удерживающую переменную: (и используйте UTF8 вместо Latin1, пока вы этим занимаетесь)

 auto queryBA = strQuery.toUtf8();
int status = sqlite3_prepare_v2(database, queryBA.data(), queryBA.size(), amp;dbStatement, 0);
 

Ответ №2:

Чтобы разгадать эту загадку, все, что нам нужно сделать, это дважды проверить, что происходит, прочитав документацию Qt.

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

Согласно документации Qt, QString toLatin1() метод ‘s возвращает QByteArray объект.

Далее мы определяем, что QByteArray data() метод возвращает «указатель [который] остается действительным до тех пор, пока массив байтов не будет перераспределен или уничтожен».

Ну, теперь проблема ясна. toLatin1() возвращает временный QByteArray объект, который, согласно обычным правилам C , управляющим временными объектами, уничтожается в конце выражения. Прежде чем это произойдет data() , возвращает указатель на его внутренности, который сохраняется query .

Но этот указатель немедленно становится указателем на освобожденную память, и любое дальнейшее использование этого указателя приводит к неопределенному поведению.

Самое простое исправление здесь — взять toLatin1 объект () и сохранить его как локальную переменную, которая уничтожается только после того, как она data() больше не нужна. Что-то вроде:

 QByteArray strarray = strQuery.toLatin1();

char *query=strarray.data();
 

Комментарии:

1. Даю ответ Ботье, потому что он ответил первым, но спасибо за объяснение. Удачного дня!!