Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
go
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
go
Commits
9fb68a9a
Commit
9fb68a9a
authored
Mar 08, 2012
by
Brad Fitzpatrick
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
database/sql{,driver}: add ErrBadConn
R=golang-dev, rsc CC=golang-dev
https://golang.org/cl/5785043
parent
b492bbe0
Changes
2
Hide whitespace changes
Inline
Side-by-side
Showing
2 changed files
with
86 additions
and
34 deletions
+86
-34
src/pkg/database/sql/driver/driver.go
src/pkg/database/sql/driver/driver.go
+11
-0
src/pkg/database/sql/sql.go
src/pkg/database/sql/sql.go
+75
-34
No files found.
src/pkg/database/sql/driver/driver.go
View file @
9fb68a9a
...
@@ -43,6 +43,17 @@ type Driver interface {
...
@@ -43,6 +43,17 @@ type Driver interface {
// documented.
// documented.
var
ErrSkip
=
errors
.
New
(
"driver: skip fast-path; continue as if unimplemented"
)
var
ErrSkip
=
errors
.
New
(
"driver: skip fast-path; continue as if unimplemented"
)
// ErrBadConn should be returned by a driver to signal to the sql
// package that a driver.Conn is in a bad state (such as the server
// having earlier closed the connection) and the sql package should
// retry on a new connection.
//
// To prevent duplicate operations, ErrBadConn should NOT be returned
// if there's a possibility that the database server might have
// performed the operation. Even if the server sends back an error,
// you shouldn't return ErrBadConn.
var
ErrBadConn
=
errors
.
New
(
"driver: bad connection"
)
// Execer is an optional interface that may be implemented by a Conn.
// Execer is an optional interface that may be implemented by a Conn.
//
//
// If a Conn does not implement Execer, the db package's DB.Exec will
// If a Conn does not implement Execer, the db package's DB.Exec will
...
...
src/pkg/database/sql/sql.go
View file @
9fb68a9a
...
@@ -251,34 +251,50 @@ func (db *DB) conn() (driver.Conn, error) {
...
@@ -251,34 +251,50 @@ func (db *DB) conn() (driver.Conn, error) {
func
(
db
*
DB
)
connIfFree
(
wanted
driver
.
Conn
)
(
conn
driver
.
Conn
,
ok
bool
)
{
func
(
db
*
DB
)
connIfFree
(
wanted
driver
.
Conn
)
(
conn
driver
.
Conn
,
ok
bool
)
{
db
.
mu
.
Lock
()
db
.
mu
.
Lock
()
defer
db
.
mu
.
Unlock
()
defer
db
.
mu
.
Unlock
()
for
n
,
conn
:=
range
db
.
freeConn
{
for
i
,
conn
:=
range
db
.
freeConn
{
if
conn
==
wanted
{
if
conn
!=
wanted
{
db
.
freeConn
[
n
]
=
db
.
freeConn
[
len
(
db
.
freeConn
)
-
1
]
continue
db
.
freeConn
=
db
.
freeConn
[
:
len
(
db
.
freeConn
)
-
1
]
return
wanted
,
true
}
}
db
.
freeConn
[
i
]
=
db
.
freeConn
[
len
(
db
.
freeConn
)
-
1
]
db
.
freeConn
=
db
.
freeConn
[
:
len
(
db
.
freeConn
)
-
1
]
return
wanted
,
true
}
}
return
nil
,
false
return
nil
,
false
}
}
func
(
db
*
DB
)
putConn
(
c
driver
.
Conn
)
{
// putConn adds a connection to the db's free pool.
// err is optionally the last error that occured on this connection.
func
(
db
*
DB
)
putConn
(
c
driver
.
Conn
,
err
error
)
{
if
err
==
driver
.
ErrBadConn
{
// Don't reuse bad connections.
return
}
db
.
mu
.
Lock
()
db
.
mu
.
Lock
()
defer
db
.
mu
.
Unlock
()
if
n
:=
len
(
db
.
freeConn
);
!
db
.
closed
&&
n
<
db
.
maxIdleConns
()
{
if
n
:=
len
(
db
.
freeConn
);
!
db
.
closed
&&
n
<
db
.
maxIdleConns
()
{
db
.
freeConn
=
append
(
db
.
freeConn
,
c
)
db
.
freeConn
=
append
(
db
.
freeConn
,
c
)
db
.
mu
.
Unlock
()
return
return
}
}
db
.
closeConn
(
c
)
// TODO(bradfitz): release lock before calling this?
// TODO: check to see if we need this Conn for any prepared
}
// statements which are still active?
db
.
mu
.
Unlock
()
func
(
db
*
DB
)
closeConn
(
c
driver
.
Conn
)
{
// TODO: check to see if we need this Conn for any prepared statements
// that are active.
c
.
Close
()
c
.
Close
()
}
}
// Prepare creates a prepared statement for later execution.
// Prepare creates a prepared statement for later execution.
func
(
db
*
DB
)
Prepare
(
query
string
)
(
*
Stmt
,
error
)
{
func
(
db
*
DB
)
Prepare
(
query
string
)
(
*
Stmt
,
error
)
{
var
stmt
*
Stmt
var
err
error
for
i
:=
0
;
i
<
10
;
i
++
{
stmt
,
err
=
db
.
prepare
(
query
)
if
err
!=
driver
.
ErrBadConn
{
break
}
}
return
stmt
,
err
}
func
(
db
*
DB
)
prepare
(
query
string
)
(
stmt
*
Stmt
,
err
error
)
{
// TODO: check if db.driver supports an optional
// TODO: check if db.driver supports an optional
// driver.Preparer interface and call that instead, if so,
// driver.Preparer interface and call that instead, if so,
// otherwise we make a prepared statement that's bound
// otherwise we make a prepared statement that's bound
...
@@ -289,12 +305,12 @@ func (db *DB) Prepare(query string) (*Stmt, error) {
...
@@ -289,12 +305,12 @@ func (db *DB) Prepare(query string) (*Stmt, error) {
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
defer
db
.
putConn
(
ci
)
defer
db
.
putConn
(
ci
,
err
)
si
,
err
:=
ci
.
Prepare
(
query
)
si
,
err
:=
ci
.
Prepare
(
query
)
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
stmt
:
=
&
Stmt
{
stmt
=
&
Stmt
{
db
:
db
,
db
:
db
,
query
:
query
,
query
:
query
,
css
:
[]
connStmt
{{
ci
,
si
}},
css
:
[]
connStmt
{{
ci
,
si
}},
...
@@ -305,15 +321,22 @@ func (db *DB) Prepare(query string) (*Stmt, error) {
...
@@ -305,15 +321,22 @@ func (db *DB) Prepare(query string) (*Stmt, error) {
// Exec executes a query without returning any rows.
// Exec executes a query without returning any rows.
func
(
db
*
DB
)
Exec
(
query
string
,
args
...
interface
{})
(
Result
,
error
)
{
func
(
db
*
DB
)
Exec
(
query
string
,
args
...
interface
{})
(
Result
,
error
)
{
sargs
,
err
:=
subsetTypeArgs
(
args
)
sargs
,
err
:=
subsetTypeArgs
(
args
)
if
err
!=
nil
{
var
res
Result
return
nil
,
err
for
i
:=
0
;
i
<
10
;
i
++
{
res
,
err
=
db
.
exec
(
query
,
sargs
)
if
err
!=
driver
.
ErrBadConn
{
break
}
}
}
return
res
,
err
}
func
(
db
*
DB
)
exec
(
query
string
,
sargs
[]
driver
.
Value
)
(
res
Result
,
err
error
)
{
ci
,
err
:=
db
.
conn
()
ci
,
err
:=
db
.
conn
()
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
defer
db
.
putConn
(
ci
)
defer
db
.
putConn
(
ci
,
err
)
if
execer
,
ok
:=
ci
.
(
driver
.
Execer
);
ok
{
if
execer
,
ok
:=
ci
.
(
driver
.
Execer
);
ok
{
resi
,
err
:=
execer
.
Exec
(
query
,
sargs
)
resi
,
err
:=
execer
.
Exec
(
query
,
sargs
)
...
@@ -364,13 +387,25 @@ func (db *DB) QueryRow(query string, args ...interface{}) *Row {
...
@@ -364,13 +387,25 @@ func (db *DB) QueryRow(query string, args ...interface{}) *Row {
// Begin starts a transaction. The isolation level is dependent on
// Begin starts a transaction. The isolation level is dependent on
// the driver.
// the driver.
func
(
db
*
DB
)
Begin
()
(
*
Tx
,
error
)
{
func
(
db
*
DB
)
Begin
()
(
*
Tx
,
error
)
{
var
tx
*
Tx
var
err
error
for
i
:=
0
;
i
<
10
;
i
++
{
tx
,
err
=
db
.
begin
()
if
err
!=
driver
.
ErrBadConn
{
break
}
}
return
tx
,
err
}
func
(
db
*
DB
)
begin
()
(
tx
*
Tx
,
err
error
)
{
ci
,
err
:=
db
.
conn
()
ci
,
err
:=
db
.
conn
()
if
err
!=
nil
{
if
err
!=
nil
{
return
nil
,
err
return
nil
,
err
}
}
txi
,
err
:=
ci
.
Begin
()
txi
,
err
:=
ci
.
Begin
()
if
err
!=
nil
{
if
err
!=
nil
{
db
.
putConn
(
ci
)
db
.
putConn
(
ci
,
err
)
return
nil
,
fmt
.
Errorf
(
"sql: failed to Begin transaction: %v"
,
err
)
return
nil
,
fmt
.
Errorf
(
"sql: failed to Begin transaction: %v"
,
err
)
}
}
return
&
Tx
{
return
&
Tx
{
...
@@ -416,7 +451,7 @@ func (tx *Tx) close() {
...
@@ -416,7 +451,7 @@ func (tx *Tx) close() {
panic
(
"double close"
)
// internal error
panic
(
"double close"
)
// internal error
}
}
tx
.
done
=
true
tx
.
done
=
true
tx
.
db
.
putConn
(
tx
.
ci
)
tx
.
db
.
putConn
(
tx
.
ci
,
nil
)
tx
.
ci
=
nil
tx
.
ci
=
nil
tx
.
txi
=
nil
tx
.
txi
=
nil
}
}
...
@@ -720,22 +755,28 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, e
...
@@ -720,22 +755,28 @@ func (s *Stmt) connStmt() (ci driver.Conn, releaseConn func(), si driver.Stmt, e
// Make a new conn if all are busy.
// Make a new conn if all are busy.
// TODO(bradfitz): or wait for one? make configurable later?
// TODO(bradfitz): or wait for one? make configurable later?
if
!
match
{
if
!
match
{
ci
,
err
:=
s
.
db
.
conn
()
for
i
:=
0
;
;
i
++
{
if
err
!=
nil
{
ci
,
err
:=
s
.
db
.
conn
()
return
nil
,
nil
,
nil
,
err
if
err
!=
nil
{
}
return
nil
,
nil
,
nil
,
err
si
,
err
:=
ci
.
Prepare
(
s
.
query
)
}
if
err
!=
nil
{
si
,
err
:=
ci
.
Prepare
(
s
.
query
)
return
nil
,
nil
,
nil
,
err
if
err
==
driver
.
ErrBadConn
&&
i
<
10
{
continue
}
if
err
!=
nil
{
return
nil
,
nil
,
nil
,
err
}
s
.
mu
.
Lock
()
cs
=
connStmt
{
ci
,
si
}
s
.
css
=
append
(
s
.
css
,
cs
)
s
.
mu
.
Unlock
()
break
}
}
s
.
mu
.
Lock
()
cs
=
connStmt
{
ci
,
si
}
s
.
css
=
append
(
s
.
css
,
cs
)
s
.
mu
.
Unlock
()
}
}
conn
:=
cs
.
ci
conn
:=
cs
.
ci
releaseConn
=
func
()
{
s
.
db
.
putConn
(
conn
)
}
releaseConn
=
func
()
{
s
.
db
.
putConn
(
conn
,
nil
)
}
return
conn
,
releaseConn
,
cs
.
si
,
nil
return
conn
,
releaseConn
,
cs
.
si
,
nil
}
}
...
@@ -759,7 +800,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
...
@@ -759,7 +800,7 @@ func (s *Stmt) Query(args ...interface{}) (*Rows, error) {
}
}
rowsi
,
err
:=
si
.
Query
(
sargs
)
rowsi
,
err
:=
si
.
Query
(
sargs
)
if
err
!=
nil
{
if
err
!=
nil
{
s
.
db
.
putConn
(
ci
)
s
.
db
.
putConn
(
ci
,
err
)
return
nil
,
err
return
nil
,
err
}
}
// Note: ownership of ci passes to the *Rows, to be freed
// Note: ownership of ci passes to the *Rows, to be freed
...
@@ -810,7 +851,7 @@ func (s *Stmt) Close() error {
...
@@ -810,7 +851,7 @@ func (s *Stmt) Close() error {
for
_
,
v
:=
range
s
.
css
{
for
_
,
v
:=
range
s
.
css
{
if
ci
,
match
:=
s
.
db
.
connIfFree
(
v
.
ci
);
match
{
if
ci
,
match
:=
s
.
db
.
connIfFree
(
v
.
ci
);
match
{
v
.
si
.
Close
()
v
.
si
.
Close
()
s
.
db
.
putConn
(
ci
)
s
.
db
.
putConn
(
ci
,
nil
)
}
else
{
}
else
{
// TODO(bradfitz): care that we can't close
// TODO(bradfitz): care that we can't close
// this statement because the statement's
// this statement because the statement's
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment