diff --git a/sqlite3.go b/sqlite3.go index 076c9bd..506a1b3 100644 --- a/sqlite3.go +++ b/sqlite3.go @@ -182,6 +182,7 @@ type SQLiteTx struct { // SQLiteStmt implement sql.Stmt. type SQLiteStmt struct { + mu sync.Mutex c *SQLiteConn s *C.sqlite3_stmt t string @@ -803,6 +804,8 @@ func (c *SQLiteConn) prepare(ctx context.Context, query string) (driver.Stmt, er // Close the statement. func (s *SQLiteStmt) Close() error { + s.mu.Lock() + defer s.mu.Unlock() if s.closed { return nil } @@ -980,7 +983,9 @@ func (s *SQLiteStmt) exec(ctx context.Context, args []namedValue) (driver.Result // Close the rows. func (rc *SQLiteRows) Close() error { + rc.s.mu.Lock() if rc.s.closed || rc.closed { + rc.s.mu.Unlock() return nil } rc.closed = true @@ -988,18 +993,23 @@ func (rc *SQLiteRows) Close() error { close(rc.done) } if rc.cls { + rc.s.mu.Unlock() return rc.s.Close() } rv := C.sqlite3_reset(rc.s.s) if rv != C.SQLITE_OK { + rc.s.mu.Unlock() return rc.s.c.lastError() } + rc.s.mu.Unlock() return nil } // Columns return column names. func (rc *SQLiteRows) Columns() []string { - if rc.nc != len(rc.cols) { + rc.s.mu.Lock() + defer rc.s.mu.Unlock() + if rc.s.s != nil && rc.nc != len(rc.cols) { rc.cols = make([]string, rc.nc) for i := 0; i < rc.nc; i++ { rc.cols[i] = C.GoString(C.sqlite3_column_name(rc.s.s, C.int(i))) @@ -1010,7 +1020,9 @@ func (rc *SQLiteRows) Columns() []string { // DeclTypes return column types. func (rc *SQLiteRows) DeclTypes() []string { - if rc.decltype == nil { + rc.s.mu.Lock() + defer rc.s.mu.Unlock() + if rc.s.s != nil && rc.decltype == nil { rc.decltype = make([]string, rc.nc) for i := 0; i < rc.nc; i++ { rc.decltype[i] = strings.ToLower(C.GoString(C.sqlite3_column_decltype(rc.s.s, C.int(i)))) @@ -1021,20 +1033,30 @@ func (rc *SQLiteRows) DeclTypes() []string { // Next move cursor to next. func (rc *SQLiteRows) Next(dest []driver.Value) error { + if rc.s.closed { + return io.EOF + } + rc.s.mu.Lock() rv := C.sqlite3_step(rc.s.s) if rv == C.SQLITE_DONE { + rc.s.mu.Unlock() return io.EOF } if rv != C.SQLITE_ROW { + defer rc.s.mu.Unlock() rv = C.sqlite3_reset(rc.s.s) if rv != C.SQLITE_OK { return rc.s.c.lastError() } + rc.s.mu.Unlock() return nil } rc.DeclTypes() + rc.s.mu.Lock() + defer rc.s.mu.Unlock() + for i := range dest { switch C.sqlite3_column_type(rc.s.s, C.int(i)) { case C.SQLITE_INTEGER: