SQLite没有绑定参数查询的结果,可与具有硬编码值的相同查询一起使用

问题描述

我遇到了sqlite 3的一个奇怪问题。我有一个相对简单的查询,该查询在其WHERE谓词中接受一个绑定参数。使用bound参数执行查询时,我得到0个结果,但是使用硬编码的值运行完全相同的查询,我得到了预期的结果数(> 0)。

我通过调用sqlite3_expanded_sql()并检查生成sql字符串,仔细检查了查询的准备情况。

我的查询带有绑定参数:

SELECT
    b.name,Y(Transform(b.geom,4326)) "y",X(Transform(b.geom,4326)) "x"
FROM buildings b
WHERE Within(b.geom,Transform(polygonFromText(?,4326),27700)) > 0

我为绑定参数提供的值:

let rectWkt = """
polyGON((
    -0.1381030196154711 51.51132617405723,-0.12929698038450965 51.51132617405723,-0.12929698038450965 51.50863378616471,-0.1381030196154711 51.50863378616471,-0.1381030196154711 51.51132617405723
))
"""

以及具有硬编码值的查询,该查询有效:

SELECT
    b.name,Transform(polygonFromText('polyGON((
    -0.1381030196154711 51.51132617405723,-0.1381030196154711 51.51132617405723
))',27700)) > 0

最后,这是sqlite3_expanded_sql()输出,在绑定上述值后调用输出

SELECT
    b.name,27700)) > 0

除非我丢失了某些内容,否则它们是相同的语句,但是执行它们时会得到完全不同的结果。

我正在使用使用Swift绑定的sqlite c API执行查询,并且已经加载了Spatialite扩展(用于几何函数)。

我检查使用我的值对sqlite3_bind_text()的呼叫是否为sqlITE_OK。当我尝试遍历结果行时没有错误,我只是将sqlITE_DONE作为第一个结果,即。结果集为空。

解决方法

我设法解决了这个问题:我需要将SQLITE_TRANSIENT作为最后一个参数传递给我 呼叫sqlite3_bind_text。我相信这是因为我呼吁执行 查询位于不同的范围内,到那时字符串值不在 范围。传递SQLITE_TRANSIENT作为第五个arg指示Sqlite使其 自己的值副本。

特别是在Swift中,需要手动将其定义为 let SQLITE_TRANSIENT = unsafeBitCast(-1,to: sqlite3_destructor_type.self) 因为它是通过Sqlite头文件中的宏定义的(请参见:https://www.sqlite.org/c3ref/c_static.html)。

我之前绑定的电话是这样的:

guard
    sqlite3_bind_text(stmnt,1,rectangleWKT,-1,nil) == SQLITE_OK
else {
    throw DatabaseError.Bind(message: errorMessage)
}

但是应该更像是:

let SQLITE_TRANSIENT = unsafeBitCast(-1,to: sqlite3_destructor_type.self)
guard
    sqlite3_bind_text(stmnt,SQLITE_TRANSIENT) == SQLITE_OK
else {
    throw DatabaseError.Bind(message: errorMessage)
}

然后,我可以将准备好的语句传递给另一个函数来执行并​​获取结果:

return loadBuildings(forStatement: stmnt)