Sqlite 没有使用绑定参数查询的结果,适用于具有硬编码值的相同查询
Sqlite no results for query with a bound parameter, works with identical query with hardcoded value
我遇到了一个关于 Sqlite 3 的奇怪问题。我有一个相对简单的查询,它在其 WHERE
谓词中采用绑定参数。使用绑定参数执行查询时,我得到 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,
Y(Transform(b.geom, 4326)) "y",
X(Transform(b.geom, 4326)) "x"
FROM buildings b
WHERE Within(b.geom, Transform(PolygonFromText('POLYGON((
-0.1381030196154711 51.51132617405723,
-0.12929698038450965 51.51132617405723,
-0.12929698038450965 51.50863378616471,
-0.1381030196154711 51.50863378616471,
-0.1381030196154711 51.51132617405723
))', 4326), 27700)) > 0
最后,这是 sqlite3_expanded_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('POLYGON((
-0.1381030196154711 51.51132617405723,
-0.12929698038450965 51.51132617405723,
-0.12929698038450965 51.50863378616471,
-0.1381030196154711 51.50863378616471,
-0.1381030196154711 51.51132617405723
))', 4326), 27700)) > 0
除非我遗漏了什么,否则这些是相同的语句,但在执行它们时我会得到完全不同的结果。
我正在使用 sqlite c API 使用 Swift 绑定执行查询,并且我已经加载了 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, 1, rectangleWKT, -1, SQLITE_TRANSIENT) == SQLITE_OK
else {
throw DatabaseError.Bind(message: errorMessage)
}
然后我可以将准备好的语句传递给另一个函数来执行并获取结果:
return loadBuildings(forStatement: stmnt)
我遇到了一个关于 Sqlite 3 的奇怪问题。我有一个相对简单的查询,它在其 WHERE
谓词中采用绑定参数。使用绑定参数执行查询时,我得到 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,
Y(Transform(b.geom, 4326)) "y",
X(Transform(b.geom, 4326)) "x"
FROM buildings b
WHERE Within(b.geom, Transform(PolygonFromText('POLYGON((
-0.1381030196154711 51.51132617405723,
-0.12929698038450965 51.51132617405723,
-0.12929698038450965 51.50863378616471,
-0.1381030196154711 51.50863378616471,
-0.1381030196154711 51.51132617405723
))', 4326), 27700)) > 0
最后,这是 sqlite3_expanded_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('POLYGON((
-0.1381030196154711 51.51132617405723,
-0.12929698038450965 51.51132617405723,
-0.12929698038450965 51.50863378616471,
-0.1381030196154711 51.50863378616471,
-0.1381030196154711 51.51132617405723
))', 4326), 27700)) > 0
除非我遗漏了什么,否则这些是相同的语句,但在执行它们时我会得到完全不同的结果。
我正在使用 sqlite c API 使用 Swift 绑定执行查询,并且我已经加载了 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, 1, rectangleWKT, -1, SQLITE_TRANSIENT) == SQLITE_OK
else {
throw DatabaseError.Bind(message: errorMessage)
}
然后我可以将准备好的语句传递给另一个函数来执行并获取结果:
return loadBuildings(forStatement: stmnt)