Merge pull request #1392 from mattn/fix-issue-1390-query-comment-panic
Fix panic when querying input with no SQL (only comments/whitespace)
diff --git a/sqlite3.go b/sqlite3.go
index 1a5433c..d59541b 100644
--- a/sqlite3.go
+++ b/sqlite3.go
@@ -1017,25 +1017,37 @@
if err != nil {
return nil, err
}
- s.(*SQLiteStmt).cls = true
+ ss := s.(*SQLiteStmt)
+ ss.cls = true
+ // sqlite3_prepare_v2 returns SQLITE_OK with a NULL statement handle
+ // when the input is empty or contains only whitespace/comments.
+ if ss.s == nil {
+ tail := ss.t
+ ss.Close()
+ if tail == "" {
+ return &SQLiteRows{cls: true, ctx: ctx}, nil
+ }
+ query = tail
+ continue
+ }
na := s.NumInput()
if len(args)-start < na {
- s.Close()
+ ss.Close()
return nil, fmt.Errorf("not enough args to execute query: want %d got %d", na, len(args)-start)
}
stmtArgs := stmtArgs(args, start, na)
- rows, err := s.(*SQLiteStmt).query(ctx, stmtArgs)
+ rows, err := ss.query(ctx, stmtArgs)
if err != nil && err != driver.ErrSkip {
- s.Close()
+ ss.Close()
return rows, err
}
start += na
- tail := s.(*SQLiteStmt).t
+ tail := ss.t
if tail == "" {
return rows, nil
}
rows.Close()
- s.Close()
+ ss.Close()
query = tail
}
}
@@ -2441,6 +2453,9 @@
// Columns return column names.
func (rc *SQLiteRows) Columns() []string {
+ if rc.s == nil {
+ return rc.cols
+ }
rc.s.mu.Lock()
defer rc.s.mu.Unlock()
if rc.s.s != nil && int(rc.nc) != len(rc.cols) {
@@ -2464,6 +2479,9 @@
// DeclTypes return column types.
func (rc *SQLiteRows) DeclTypes() []string {
+ if rc.s == nil {
+ return rc.decltype
+ }
rc.s.mu.Lock()
defer rc.s.mu.Unlock()
return rc.declTypes()
@@ -2471,6 +2489,9 @@
// Next move cursor to next. Attempts to honor context timeout from QueryContext call.
func (rc *SQLiteRows) Next(dest []driver.Value) error {
+ if rc.s == nil {
+ return io.EOF
+ }
rc.s.mu.Lock()
defer rc.s.mu.Unlock()
diff --git a/sqlite3_test.go b/sqlite3_test.go
index 852aa10..ac81458 100644
--- a/sqlite3_test.go
+++ b/sqlite3_test.go
@@ -2065,6 +2065,40 @@
}
}
+// https://github.com/mattn/go-sqlite3/issues/1390
+// sqlite3_prepare_v2 returns SQLITE_OK with a NULL statement handle when the
+// input contains no SQL (only whitespace or comments). Querying such input
+// must not panic.
+func TestQueryCommentOnly(t *testing.T) {
+ db, err := sql.Open("sqlite3", ":memory:")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer db.Close()
+
+ cases := []string{"", " ", "-- comment", "---- comment\n", "/* block */"}
+ for _, q := range cases {
+ var x int
+ if err := db.QueryRow(q).Scan(&x); err != sql.ErrNoRows {
+ t.Errorf("QueryRow(%q): expected ErrNoRows, got %v", q, err)
+ }
+
+ rows, err := db.Query(q)
+ if err != nil {
+ t.Errorf("Query(%q): unexpected error: %v", q, err)
+ continue
+ }
+ if rows.Next() {
+ t.Errorf("Query(%q): expected no rows", q)
+ }
+ rows.Close()
+
+ if _, err := db.Exec(q); err != nil {
+ t.Errorf("Exec(%q): unexpected error: %v", q, err)
+ }
+ }
+}
+
var customFunctionOnce sync.Once
func BenchmarkCustomFunctions(b *testing.B) {