diff --git a/internal/sqladapter/database.go b/internal/sqladapter/database.go index 9d7370fd826287eb0ded04893827e7662b98ff44..7c1fa4d0c33fb8c2bf1ed909d07562ab333f95bf 100644 --- a/internal/sqladapter/database.go +++ b/internal/sqladapter/database.go @@ -359,8 +359,10 @@ func (d *database) prepareStatement(stmt *exql.Statement) (*Stmt, string, error) pc, ok := d.cachedStatements.ReadRaw(stmt) if ok { // The statement was cached. - ps := pc.(*Stmt).Open() - return ps, ps.query, nil + ps, err := pc.(*Stmt).Open() + if err == nil { + return ps, ps.query, nil + } } // Plain SQL query. diff --git a/internal/sqladapter/statement.go b/internal/sqladapter/statement.go index 0a8a4482e894fb1d4d86c00b2df387a98f9aaf7e..a57a3aede82d7225b2bd605e14a03963597feeea 100644 --- a/internal/sqladapter/statement.go +++ b/internal/sqladapter/statement.go @@ -2,6 +2,7 @@ package sqladapter import ( "database/sql" + "errors" "sync/atomic" ) @@ -39,19 +40,23 @@ func NewStatement(stmt *sql.Stmt, query string) *Stmt { } // Open marks the statement as in-use -func (c *Stmt) Open() *Stmt { +func (c *Stmt) Open() (*Stmt, error) { + if atomic.LoadInt32(&c.dead) > 0 { + return nil, errors.New("statement is dead") + } atomic.AddInt64(&c.count, 1) - return c + return c, nil } // Close closes the underlying statement if no other go-routine is using it. func (c *Stmt) Close() { if atomic.AddInt64(&c.count, -1) > 0 { - // There are another goroutines using this statement so we don't want to - // close it for real. + // If this counter is more than 0 then there are other goroutines using + // this statement so we don't want to close it for real. return } - if atomic.LoadInt32(&c.dead) > 0 { + + if atomic.LoadInt32(&c.dead) > 0 && atomic.LoadInt64(&c.count) <= 0 { // Statement is dead and we can close it for real. c.Stmt.Close() // Reduce active statements counter.