diff --git a/callbacks.go b/callbacks.go index 6d6b23b..4e622b4 100644 --- a/callbacks.go +++ b/callbacks.go @@ -36,7 +36,7 @@ func errHandler(dbprocAddr C.long, severity, dberr, oserr C.int, dberrstr, oserr conn := getConnection(int64(dbprocAddr)) if conn != nil { - conn.addError(err) + conn.addError(err, int(dberr)) } //fmt.Printf("err: %s", err) diff --git a/conn.go b/conn.go index e8cc296..ac18d7c 100644 --- a/conn.go +++ b/conn.go @@ -94,6 +94,9 @@ type Conn struct { messageNums map[int]int messageMutex sync.RWMutex + errors map[int]string + errorsMutex sync.RWMutex + currentResult *Result expiresFromPool time.Time belongsToPool *ConnPool @@ -120,7 +123,12 @@ func (conn *Conn) addMessage(msg string, msgno int) { conn.messageNums[msgno] = i + 1 } -func (conn *Conn) addError(err string) { +func (conn *Conn) addError(err string, errno int) { + conn.errorsMutex.Lock() + defer conn.errorsMutex.Unlock() + + conn.errors[errno] = err + if len(conn.Error) > 0 { conn.Error += "\n" } @@ -141,6 +149,7 @@ func connectWithCredentials(crd *credentials) (*Conn, error) { spParamsCache: NewParamsCache(), credentials: *crd, messageNums: make(map[int]int), + errors: make(map[int]string), } err := conn.reconnect() if err != nil { @@ -188,6 +197,14 @@ func (conn *Conn) close() { } } +// Remove a pooled connection from it's pool. +func RemoveFromPool(conn *Conn) *Conn { + if conn.belongsToPool != nil { + conn.belongsToPool.Remove(conn) + } + return conn +} + //ensure only one getDbProc at a time var getDbProcMutex = &sync.Mutex{} @@ -260,11 +277,15 @@ func (conn *Conn) DbUse() error { func (conn *Conn) clearMessages() { conn.messageMutex.Lock() - defer conn.messageMutex.Unlock() + conn.errorsMutex.Lock() conn.Error = "" + conn.errors = make(map[int]string) conn.Message = "" conn.messageNums = make(map[int]int) + + conn.errorsMutex.Lock() + conn.messageMutex.Unlock() } //Returns the number of occurances of a supplied FreeTDS message number. @@ -276,6 +297,15 @@ func (conn *Conn) HasMessageNumber(msgno int) int { return count } +//Returns the error string for a supplied FreeTDS error number. +//if the error has not occurred then an empty string and false is returned. +func (conn *Conn) HasErrorNumber(errno int) (string, bool) { + conn.errorsMutex.RLock() + err, found := conn.errors[errno] + conn.errorsMutex.RUnlock() + return err, found +} + //Execute sql query. func (conn *Conn) Exec(sql string) ([]*Result, error) { results, err := conn.exec(sql) diff --git a/conn_pool.go b/conn_pool.go index a48bd76..cfd8064 100644 --- a/conn_pool.go +++ b/conn_pool.go @@ -167,6 +167,17 @@ func (p *ConnPool) addToPool(conn *Conn) { } } +// Remove a pooled connection from the pool, +// forcing a new connection to take it's place. +func (p *ConnPool) Remove(conn *Conn) { + if conn.belongsToPool != p { + return + } + p.connCount-- + <-p.poolGuard //remove reservation + conn.belongsToPool = nil +} + //Release connection to the pool. func (p *ConnPool) Release(conn *Conn) { if conn.belongsToPool != p { diff --git a/conn_sp.go b/conn_sp.go index d58882e..5a621f4 100644 --- a/conn_sp.go +++ b/conn_sp.go @@ -49,7 +49,7 @@ func (conn *Conn) ExecSp(spName string, params ...interface{}) (*SpResult, error return nil, err } for i, spParam := range spParams { - //get datavalue for the suplied stored procedure parametar + //get datavalue for the suplied stored procedure parameter var datavalue *C.BYTE datalen := 0 if i < len(params) { @@ -57,7 +57,7 @@ func (conn *Conn) ExecSp(spName string, params ...interface{}) (*SpResult, error if param != nil { data, sqlDatalen, err := typeToSqlBuf(int(spParam.UserTypeId), param, conn.freetdsVersionGte095) if err != nil { - conn.Close() //close the connection + conn.close() //hard close the connection, if pooled don't return it. return nil, err } if len(data) > 0 {