SQLite3 INSERT 查询的随机语法错误
Random syntax error on SQLite3 INSERT query
我在 Qt 上使用 SQLite3 和 Spatialite 进行插入查询,有时它只是无法返回随机语法错误。
如果我 运行 在 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(), &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
strQuery.toLatin1()
是临时值,.data()
获取该值内的指针。这实际上是一个悬挂指针。
添加一个中间保持变量:(并使用 UTF8 而不是 Latin1)
auto queryBA = strQuery.toUtf8();
int status = sqlite3_prepare_v2(database, queryBA.data(), queryBA.size(), &dbStatement, 0);
要解开这个谜,我们所要做的就是通过阅读 Qt 的文档仔细检查发生了什么。
char *query = strQuery.toLatin1().data();
根据 Qt 的文档,QString
的 toLatin1()
method returns a QByteArray
对象。
接下来,我们确定 QByteArray
的 data()
方法 returns 一个 "pointer [that] remains valid as long as the byte array isn't reallocated or destroyed".
好了,到此,问题就清楚了。 toLatin1()
returns 一个临时 QByteArray
对象,根据 C++ 管理临时对象的通常规则,它在表达式末尾被销毁。在此之前 data()
returns 指向其内部的指针,保存在 query
.
但是该指针立即变成指向已释放内存的指针,任何进一步使用该指针都会导致未定义的行为。
此处最简单的解决方法是获取 toLatin1
() 的对象,并将其保存为局部变量,只有在不再需要其 data()
后才会销毁。类似于:
QByteArray strarray = strQuery.toLatin1();
char *query=strarray.data();
我在 Qt 上使用 SQLite3 和 Spatialite 进行插入查询,有时它只是无法返回随机语法错误。 如果我 运行 在 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(), &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
strQuery.toLatin1()
是临时值,.data()
获取该值内的指针。这实际上是一个悬挂指针。
添加一个中间保持变量:(并使用 UTF8 而不是 Latin1)
auto queryBA = strQuery.toUtf8();
int status = sqlite3_prepare_v2(database, queryBA.data(), queryBA.size(), &dbStatement, 0);
要解开这个谜,我们所要做的就是通过阅读 Qt 的文档仔细检查发生了什么。
char *query = strQuery.toLatin1().data();
根据 Qt 的文档,QString
的 toLatin1()
method returns a QByteArray
对象。
接下来,我们确定 QByteArray
的 data()
方法 returns 一个 "pointer [that] remains valid as long as the byte array isn't reallocated or destroyed".
好了,到此,问题就清楚了。 toLatin1()
returns 一个临时 QByteArray
对象,根据 C++ 管理临时对象的通常规则,它在表达式末尾被销毁。在此之前 data()
returns 指向其内部的指针,保存在 query
.
但是该指针立即变成指向已释放内存的指针,任何进一步使用该指针都会导致未定义的行为。
此处最简单的解决方法是获取 toLatin1
() 的对象,并将其保存为局部变量,只有在不再需要其 data()
后才会销毁。类似于:
QByteArray strarray = strQuery.toLatin1();
char *query=strarray.data();