Merge pull request #1392 from mattn/fix-issue-1390-query-comment-panic
Fix panic when querying input with no SQL (only comments/whitespace)
This commit is contained in:
33
sqlite3.go
33
sqlite3.go
@@ -1017,25 +1017,37 @@ func (c *SQLiteConn) query(ctx context.Context, query string, args []driver.Name
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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()
|
na := s.NumInput()
|
||||||
if len(args)-start < na {
|
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)
|
return nil, fmt.Errorf("not enough args to execute query: want %d got %d", na, len(args)-start)
|
||||||
}
|
}
|
||||||
stmtArgs := stmtArgs(args, start, na)
|
stmtArgs := stmtArgs(args, start, na)
|
||||||
rows, err := s.(*SQLiteStmt).query(ctx, stmtArgs)
|
rows, err := ss.query(ctx, stmtArgs)
|
||||||
if err != nil && err != driver.ErrSkip {
|
if err != nil && err != driver.ErrSkip {
|
||||||
s.Close()
|
ss.Close()
|
||||||
return rows, err
|
return rows, err
|
||||||
}
|
}
|
||||||
start += na
|
start += na
|
||||||
tail := s.(*SQLiteStmt).t
|
tail := ss.t
|
||||||
if tail == "" {
|
if tail == "" {
|
||||||
return rows, nil
|
return rows, nil
|
||||||
}
|
}
|
||||||
rows.Close()
|
rows.Close()
|
||||||
s.Close()
|
ss.Close()
|
||||||
query = tail
|
query = tail
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2441,6 +2453,9 @@ func (rc *SQLiteRows) Close() error {
|
|||||||
|
|
||||||
// Columns return column names.
|
// Columns return column names.
|
||||||
func (rc *SQLiteRows) Columns() []string {
|
func (rc *SQLiteRows) Columns() []string {
|
||||||
|
if rc.s == nil {
|
||||||
|
return rc.cols
|
||||||
|
}
|
||||||
rc.s.mu.Lock()
|
rc.s.mu.Lock()
|
||||||
defer rc.s.mu.Unlock()
|
defer rc.s.mu.Unlock()
|
||||||
if rc.s.s != nil && int(rc.nc) != len(rc.cols) {
|
if rc.s.s != nil && int(rc.nc) != len(rc.cols) {
|
||||||
@@ -2464,6 +2479,9 @@ func (rc *SQLiteRows) declTypes() []string {
|
|||||||
|
|
||||||
// DeclTypes return column types.
|
// DeclTypes return column types.
|
||||||
func (rc *SQLiteRows) DeclTypes() []string {
|
func (rc *SQLiteRows) DeclTypes() []string {
|
||||||
|
if rc.s == nil {
|
||||||
|
return rc.decltype
|
||||||
|
}
|
||||||
rc.s.mu.Lock()
|
rc.s.mu.Lock()
|
||||||
defer rc.s.mu.Unlock()
|
defer rc.s.mu.Unlock()
|
||||||
return rc.declTypes()
|
return rc.declTypes()
|
||||||
@@ -2471,6 +2489,9 @@ func (rc *SQLiteRows) DeclTypes() []string {
|
|||||||
|
|
||||||
// Next move cursor to next. Attempts to honor context timeout from QueryContext call.
|
// Next move cursor to next. Attempts to honor context timeout from QueryContext call.
|
||||||
func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
func (rc *SQLiteRows) Next(dest []driver.Value) error {
|
||||||
|
if rc.s == nil {
|
||||||
|
return io.EOF
|
||||||
|
}
|
||||||
rc.s.mu.Lock()
|
rc.s.mu.Lock()
|
||||||
defer rc.s.mu.Unlock()
|
defer rc.s.mu.Unlock()
|
||||||
|
|
||||||
|
|||||||
@@ -2065,6 +2065,40 @@ func TestNamedParamClearBindings(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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
|
var customFunctionOnce sync.Once
|
||||||
|
|
||||||
func BenchmarkCustomFunctions(b *testing.B) {
|
func BenchmarkCustomFunctions(b *testing.B) {
|
||||||
|
|||||||
Reference in New Issue
Block a user