Empty query causes loop
By mistake stupid me executed an empty query. This resulted in an (infinite?) loop and hanged my application.
The minimal example below reproduces this. This example uses an in-memory database, but it occurs with a database file as well.
Version: v1.14.7
db, err := sql.Open("sqlite3", ":memory:")
if err != nil {
panic(err)
}
defer db.Close()
stmt, err := db.Prepare("") // empty query
if err != nil {
panic(err)
}
defer stmt.Close()
rows, err := stmt.Query()
if err != nil {
panic(err)
}
defer rows.Close()
count := 0
for rows.Next() {
var dummy string
rows.Scan(&dummy) // this can be omitted
log.Printf("%d: [%+v]\n", count, dummy)
count++
}
Results in:
0: []
1: []
2: []
3: []
4: []
...
I don't know what the expected behavior should be. Maybe return an error?
The source of the bug is that sqlite3_prepare_v2 produces a null *sqlite3_stmt with no error when you do this. But this library does not check for that. https://github.com/mattn/go-sqlite3/blob/d33341ff0d20a3b46047dba17ad897b40705c563/sqlite3.go#L1749-L1752
Compounding the issue, each call to sqlite3_step will fail with SQLITE_MISUSE, but it gets dropped because of this:
https://github.com/mattn/go-sqlite3/blob/d33341ff0d20a3b46047dba17ad897b40705c563/sqlite3.go#L2105-L2111
Basically, sqlite3_reset always vacuously succeeds when given a null statement, so we end up returning null from each call to Next(). Thus the loop never terminates.
In short, there are two bugs in play:
- If
sqlite3_prepare_v2yieldsSQLITE_OKwith a null prepared statement it should be treated as an error. - If
sqlite3_resetyieldsSQLITE_OKaftersqlite3_stepfails we should still return an error. (Note: We can't just calllastError()in a situation like this since it might not be set properly. Maybe just convert to anErrNo?)