Qt环境下SQLite3+Spatialite执行INSERT查询随机出现语法错误
问题根本原因
- 野指针访问内存:你代码中获取SQL字符串C风格指针的逻辑存在严重错误:
行char *query = strQuery.toLatin1().data();中,strQuery.toLatin1()返回的是临时QByteArray对象,该对象在当前语句执行完成后就会被自动析构,其内部存储的字符串内存也会被释放。后续sqlite3_prepare_v2调用读取query指向的已经被释放的内存时,内容是随机的:如果内存还未被其他数据覆写,SQL执行正常;如果已经被覆写为垃圾数据,就会出现你遇到的随机语法错误(比如报错里的乱码、随机关键字报错)。 - 你将生成的SQL复制到SpatialiteGUI中运行始终正常,是因为复制的是未被破坏的正确SQL字符串,不存在内存损坏问题。
修复方案
快速修复(直接解决野指针问题)
将SQL字符串转C指针的逻辑修改为保留临时字节数组对象,避免提前析构即可:
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) + ";"; // 修改开始:保留字节数组对象避免提前释放,用Utf8兼容更多场景 QByteArray queryByteArray = strQuery.toUtf8(); const char* query = queryByteArray.constData(); int status = sqlite3_prepare_v2(database, query, queryByteArray.size(), &dbStatement, 0); // 修改结束 if(status == SQLITE_OK) { int stepStatus = sqlite3_step(dbStatement); if(stepStatus == SQLITE_DONE) inserted = true; }else qDebug().noquote() << "status:" << status << "error:" << sqlite3_errmsg(database); sqlite3_finalize(dbStatement); return inserted; }
修改后queryByteArray是当前函数的局部变量,直到函数执行完成才会销毁,query指针全程指向有效内存,不会再出现随机内容损坏问题。
优化方案(更安全高效)
你当前直接拼接SQL字符串的方式存在SQL注入风险,且批量插入效率较低,建议改用SQLite预编译参数绑定逻辑实现:
- 预编译固定模板的插入语句:
INSERT INTO "WORK_xxx" (Geometry) VALUES (GeomFromText(?, 4326)) - 循环绑定每个多边形的WKT字符串参数,执行step后重置语句,批量插入性能更高也更安全。
内容的提问来源于stack exchange,提问作者JonatasCV
相关产品推荐
相关产品推荐

