libgo: update to go1.9
Reviewed-on: https://go-review.googlesource.com/63753 From-SVN: r252767
This commit is contained in:
parent
a41a6142df
commit
bc998d034f
985 changed files with 56892 additions and 20449 deletions
|
@ -139,6 +139,7 @@ func closeDB(t testing.TB, db *DB) {
|
|||
t.Errorf("Error closing fakeConn: %v", err)
|
||||
}
|
||||
})
|
||||
db.mu.Lock()
|
||||
for i, dc := range db.freeConn {
|
||||
if n := len(dc.openStmt); n > 0 {
|
||||
// Just a sanity check. This is legal in
|
||||
|
@ -149,6 +150,8 @@ func closeDB(t testing.TB, db *DB) {
|
|||
t.Errorf("while closing db, freeConn %d/%d had %d open stmts; want 0", i, len(db.freeConn), n)
|
||||
}
|
||||
}
|
||||
db.mu.Unlock()
|
||||
|
||||
err := db.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("error closing DB: %v", err)
|
||||
|
@ -322,7 +325,7 @@ func TestQueryContext(t *testing.T) {
|
|||
select {
|
||||
case <-ctx.Done():
|
||||
if err := ctx.Err(); err != context.Canceled {
|
||||
t.Fatalf("context err = %v; want context.Canceled", ctx.Err())
|
||||
t.Fatalf("context err = %v; want context.Canceled", err)
|
||||
}
|
||||
default:
|
||||
t.Fatalf("context err = nil; want context.Canceled")
|
||||
|
@ -413,7 +416,7 @@ func TestTxContextWait(t *testing.T) {
|
|||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond*15)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 15*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
|
@ -590,13 +593,13 @@ func TestPoolExhaustOnCancel(t *testing.T) {
|
|||
saturate.Wait()
|
||||
|
||||
// Now cancel the request while it is waiting.
|
||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 2*time.Second)
|
||||
defer cancel()
|
||||
|
||||
for i := 0; i < max; i++ {
|
||||
ctxReq, cancelReq := context.WithCancel(ctx)
|
||||
go func() {
|
||||
time.Sleep(time.Millisecond * 100)
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
cancelReq()
|
||||
}()
|
||||
err := db.PingContext(ctxReq)
|
||||
|
@ -874,7 +877,7 @@ func TestStatementClose(t *testing.T) {
|
|||
msg string
|
||||
}{
|
||||
{&Stmt{stickyErr: want}, "stickyErr not propagated"},
|
||||
{&Stmt{tx: &Tx{}, txds: &driverStmt{Locker: &sync.Mutex{}, si: stubDriverStmt{want}}}, "driverStmt.Close() error not propagated"},
|
||||
{&Stmt{cg: &Tx{}, cgds: &driverStmt{Locker: &sync.Mutex{}, si: stubDriverStmt{want}}}, "driverStmt.Close() error not propagated"},
|
||||
}
|
||||
for _, test := range tests {
|
||||
if err := test.stmt.Close(); err != want {
|
||||
|
@ -1024,6 +1027,196 @@ func TestTxStmt(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestTxStmtPreparedOnce(t *testing.T) {
|
||||
db := newTestDB(t, "")
|
||||
defer closeDB(t, db)
|
||||
exec(t, db, "CREATE|t1|name=string,age=int32")
|
||||
|
||||
prepares0 := numPrepares(t, db)
|
||||
|
||||
// db.Prepare increments numPrepares.
|
||||
stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
|
||||
if err != nil {
|
||||
t.Fatalf("Stmt, err = %v, %v", stmt, err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
t.Fatalf("Begin = %v", err)
|
||||
}
|
||||
|
||||
txs1 := tx.Stmt(stmt)
|
||||
txs2 := tx.Stmt(stmt)
|
||||
|
||||
_, err = txs1.Exec("Go", 7)
|
||||
if err != nil {
|
||||
t.Fatalf("Exec = %v", err)
|
||||
}
|
||||
txs1.Close()
|
||||
|
||||
_, err = txs2.Exec("Gopher", 8)
|
||||
if err != nil {
|
||||
t.Fatalf("Exec = %v", err)
|
||||
}
|
||||
txs2.Close()
|
||||
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
t.Fatalf("Commit = %v", err)
|
||||
}
|
||||
|
||||
if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
|
||||
t.Errorf("executed %d Prepare statements; want 1", prepares)
|
||||
}
|
||||
}
|
||||
|
||||
func TestTxStmtClosedRePrepares(t *testing.T) {
|
||||
db := newTestDB(t, "")
|
||||
defer closeDB(t, db)
|
||||
exec(t, db, "CREATE|t1|name=string,age=int32")
|
||||
|
||||
prepares0 := numPrepares(t, db)
|
||||
|
||||
// db.Prepare increments numPrepares.
|
||||
stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
|
||||
if err != nil {
|
||||
t.Fatalf("Stmt, err = %v, %v", stmt, err)
|
||||
}
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
t.Fatalf("Begin = %v", err)
|
||||
}
|
||||
err = stmt.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("stmt.Close() = %v", err)
|
||||
}
|
||||
// tx.Stmt increments numPrepares because stmt is closed.
|
||||
txs := tx.Stmt(stmt)
|
||||
if txs.stickyErr != nil {
|
||||
t.Fatal(txs.stickyErr)
|
||||
}
|
||||
if txs.parentStmt != nil {
|
||||
t.Fatal("expected nil parentStmt")
|
||||
}
|
||||
_, err = txs.Exec(`Eric`, 82)
|
||||
if err != nil {
|
||||
t.Fatalf("txs.Exec = %v", err)
|
||||
}
|
||||
|
||||
err = txs.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("txs.Close = %v", err)
|
||||
}
|
||||
|
||||
tx.Rollback()
|
||||
|
||||
if prepares := numPrepares(t, db) - prepares0; prepares != 2 {
|
||||
t.Errorf("executed %d Prepare statements; want 2", prepares)
|
||||
}
|
||||
}
|
||||
|
||||
func TestParentStmtOutlivesTxStmt(t *testing.T) {
|
||||
db := newTestDB(t, "")
|
||||
defer closeDB(t, db)
|
||||
exec(t, db, "CREATE|t1|name=string,age=int32")
|
||||
|
||||
// Make sure everything happens on the same connection.
|
||||
db.SetMaxOpenConns(1)
|
||||
|
||||
prepares0 := numPrepares(t, db)
|
||||
|
||||
// db.Prepare increments numPrepares.
|
||||
stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
|
||||
if err != nil {
|
||||
t.Fatalf("Stmt, err = %v, %v", stmt, err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
t.Fatalf("Begin = %v", err)
|
||||
}
|
||||
txs := tx.Stmt(stmt)
|
||||
if len(stmt.css) != 1 {
|
||||
t.Fatalf("len(stmt.css) = %v; want 1", len(stmt.css))
|
||||
}
|
||||
err = txs.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("txs.Close() = %v", err)
|
||||
}
|
||||
err = tx.Rollback()
|
||||
if err != nil {
|
||||
t.Fatalf("tx.Rollback() = %v", err)
|
||||
}
|
||||
// txs must not be valid.
|
||||
_, err = txs.Exec("Suzan", 30)
|
||||
if err == nil {
|
||||
t.Fatalf("txs.Exec(), expected err")
|
||||
}
|
||||
// Stmt must still be valid.
|
||||
_, err = stmt.Exec("Janina", 25)
|
||||
if err != nil {
|
||||
t.Fatalf("stmt.Exec() = %v", err)
|
||||
}
|
||||
|
||||
if prepares := numPrepares(t, db) - prepares0; prepares != 1 {
|
||||
t.Errorf("executed %d Prepare statements; want 1", prepares)
|
||||
}
|
||||
}
|
||||
|
||||
// Test that tx.Stmt called with a statement already
|
||||
// associated with tx as argument re-prepares the same
|
||||
// statement again.
|
||||
func TestTxStmtFromTxStmtRePrepares(t *testing.T) {
|
||||
db := newTestDB(t, "")
|
||||
defer closeDB(t, db)
|
||||
exec(t, db, "CREATE|t1|name=string,age=int32")
|
||||
prepares0 := numPrepares(t, db)
|
||||
// db.Prepare increments numPrepares.
|
||||
stmt, err := db.Prepare("INSERT|t1|name=?,age=?")
|
||||
if err != nil {
|
||||
t.Fatalf("Stmt, err = %v, %v", stmt, err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
t.Fatalf("Begin = %v", err)
|
||||
}
|
||||
txs1 := tx.Stmt(stmt)
|
||||
|
||||
// tx.Stmt(txs1) increments numPrepares because txs1 already
|
||||
// belongs to a transaction (albeit the same transaction).
|
||||
txs2 := tx.Stmt(txs1)
|
||||
if txs2.stickyErr != nil {
|
||||
t.Fatal(txs2.stickyErr)
|
||||
}
|
||||
if txs2.parentStmt != nil {
|
||||
t.Fatal("expected nil parentStmt")
|
||||
}
|
||||
_, err = txs2.Exec(`Eric`, 82)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
err = txs1.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("txs1.Close = %v", err)
|
||||
}
|
||||
err = txs2.Close()
|
||||
if err != nil {
|
||||
t.Fatalf("txs1.Close = %v", err)
|
||||
}
|
||||
err = tx.Rollback()
|
||||
if err != nil {
|
||||
t.Fatalf("tx.Rollback = %v", err)
|
||||
}
|
||||
|
||||
if prepares := numPrepares(t, db) - prepares0; prepares != 2 {
|
||||
t.Errorf("executed %d Prepare statements; want 2", prepares)
|
||||
}
|
||||
}
|
||||
|
||||
// Issue: https://golang.org/issue/2784
|
||||
// This test didn't fail before because we got lucky with the fakedb driver.
|
||||
// It was failing, and now not, in github.com/bradfitz/go-sql-test
|
||||
|
@ -1108,6 +1301,69 @@ func TestTxErrBadConn(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
func TestConnQuery(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
conn, err := db.Conn(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
var name string
|
||||
err = conn.QueryRowContext(ctx, "SELECT|people|name|age=?", 3).Scan(&name)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if name != "Chris" {
|
||||
t.Fatalf("unexpected result, got %q want Chris", name)
|
||||
}
|
||||
|
||||
err = conn.PingContext(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnTx(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
conn, err := db.Conn(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
tx, err := conn.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
insertName, insertAge := "Nancy", 33
|
||||
_, err = tx.ExecContext(ctx, "INSERT|people|name=?,age=?,photo=APHOTO", insertName, insertAge)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = tx.Commit()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
var selectName string
|
||||
err = conn.QueryRowContext(ctx, "SELECT|people|name|age=?", insertAge).Scan(&selectName)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if selectName != insertName {
|
||||
t.Fatalf("got %q want %q", selectName, insertName)
|
||||
}
|
||||
}
|
||||
|
||||
// Tests fix for issue 2542, that we release a lock when querying on
|
||||
// a closed connection.
|
||||
func TestIssue2542Deadlock(t *testing.T) {
|
||||
|
@ -1831,8 +2087,8 @@ func TestConnMaxLifetime(t *testing.T) {
|
|||
}
|
||||
|
||||
// Expire first conn
|
||||
offset = time.Second * 11
|
||||
db.SetConnMaxLifetime(time.Second * 10)
|
||||
offset = 11 * time.Second
|
||||
db.SetConnMaxLifetime(10 * time.Second)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -2078,9 +2334,13 @@ func TestStmtCloseOrder(t *testing.T) {
|
|||
// Test cases where there's more than maxBadConnRetries bad connections in the
|
||||
// pool (issue 8834)
|
||||
func TestManyErrBadConn(t *testing.T) {
|
||||
manyErrBadConnSetup := func() *DB {
|
||||
manyErrBadConnSetup := func(first ...func(db *DB)) *DB {
|
||||
db := newTestDB(t, "people")
|
||||
|
||||
for _, f := range first {
|
||||
f(db)
|
||||
}
|
||||
|
||||
nconn := maxBadConnRetries + 1
|
||||
db.SetMaxIdleConns(nconn)
|
||||
db.SetMaxOpenConns(nconn)
|
||||
|
@ -2148,6 +2408,128 @@ func TestManyErrBadConn(t *testing.T) {
|
|||
if err = stmt.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Stmt.Exec
|
||||
db = manyErrBadConnSetup(func(db *DB) {
|
||||
stmt, err = db.Prepare("INSERT|people|name=Julia,age=19")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
defer closeDB(t, db)
|
||||
_, err = stmt.Exec()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = stmt.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Stmt.Query
|
||||
db = manyErrBadConnSetup(func(db *DB) {
|
||||
stmt, err = db.Prepare("SELECT|people|age,name|")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
})
|
||||
defer closeDB(t, db)
|
||||
rows, err = stmt.Query()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = rows.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err = stmt.Close(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Conn
|
||||
db = manyErrBadConnSetup()
|
||||
defer closeDB(t, db)
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
conn, err := db.Conn(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = conn.Close()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Ping
|
||||
db = manyErrBadConnSetup()
|
||||
defer closeDB(t, db)
|
||||
err = db.PingContext(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
// TestIssue20575 ensures the Rows from query does not block
|
||||
// closing a transaction. Ensure Rows is closed while closing a trasaction.
|
||||
func TestIssue20575(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second)
|
||||
defer cancel()
|
||||
_, err = tx.QueryContext(ctx, "SELECT|people|age,name|")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
// Do not close Rows from QueryContext.
|
||||
err = tx.Rollback()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
select {
|
||||
default:
|
||||
case <-ctx.Done():
|
||||
t.Fatal("timeout: failed to rollback query without closing rows:", ctx.Err())
|
||||
}
|
||||
}
|
||||
|
||||
// TestIssue20622 tests closing the transaction before rows is closed, requires
|
||||
// the race detector to fail.
|
||||
func TestIssue20622(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
tx, err := db.BeginTx(ctx, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
rows, err := tx.Query("SELECT|people|age,name|")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
count := 0
|
||||
for rows.Next() {
|
||||
count++
|
||||
var age int
|
||||
var name string
|
||||
if err := rows.Scan(&age, &name); err != nil {
|
||||
t.Fatal("scan failed", err)
|
||||
}
|
||||
|
||||
if count == 1 {
|
||||
cancel()
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
}
|
||||
rows.Close()
|
||||
tx.Commit()
|
||||
}
|
||||
|
||||
// golang.org/issue/5718
|
||||
|
@ -2751,7 +3133,7 @@ func TestIssue18429(t *testing.T) {
|
|||
if err != nil {
|
||||
return
|
||||
}
|
||||
// This is expected to give a cancel error many, but not all the time.
|
||||
// This is expected to give a cancel error most, but not all the time.
|
||||
// Test failure will happen with a panic or other race condition being
|
||||
// reported.
|
||||
rows, _ := tx.QueryContext(ctx, "WAIT|"+qwait+"|SELECT|people|name|")
|
||||
|
@ -2766,6 +3148,46 @@ func TestIssue18429(t *testing.T) {
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
// TestIssue20160 attempts to test a short context life on a stmt Query.
|
||||
func TestIssue20160(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
ctx := context.Background()
|
||||
sem := make(chan bool, 20)
|
||||
var wg sync.WaitGroup
|
||||
|
||||
const milliWait = 30
|
||||
|
||||
stmt, err := db.PrepareContext(ctx, "SELECT|people|name|")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
for i := 0; i < 100; i++ {
|
||||
sem <- true
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
defer func() {
|
||||
<-sem
|
||||
wg.Done()
|
||||
}()
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Duration(rand.Intn(milliWait))*time.Millisecond)
|
||||
defer cancel()
|
||||
|
||||
// This is expected to give a cancel error most, but not all the time.
|
||||
// Test failure will happen with a panic or other race condition being
|
||||
// reported.
|
||||
rows, _ := stmt.QueryContext(ctx)
|
||||
if rows != nil {
|
||||
rows.Close()
|
||||
}
|
||||
}()
|
||||
}
|
||||
wg.Wait()
|
||||
}
|
||||
|
||||
// TestIssue18719 closes the context right before use. The sql.driverConn
|
||||
// will nil out the ci on close in a lock, but if another process uses it right after
|
||||
// it will panic with on the nil ref.
|
||||
|
@ -2788,7 +3210,7 @@ func TestIssue18719(t *testing.T) {
|
|||
|
||||
// Wait for the context to cancel and tx to rollback.
|
||||
for tx.isDone() == false {
|
||||
time.Sleep(time.Millisecond * 3)
|
||||
time.Sleep(3 * time.Millisecond)
|
||||
}
|
||||
}
|
||||
defer func() { hookTxGrabConn = nil }()
|
||||
|
@ -2807,19 +3229,64 @@ func TestIssue18719(t *testing.T) {
|
|||
// canceled context.
|
||||
|
||||
cancel()
|
||||
waitForRowsClose(t, rows, 5*time.Second)
|
||||
}
|
||||
|
||||
func TestIssue20647(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
conn, err := db.Conn(ctx)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
stmt, err := conn.PrepareContext(ctx, "SELECT|people|name|")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer stmt.Close()
|
||||
|
||||
rows1, err := stmt.QueryContext(ctx)
|
||||
if err != nil {
|
||||
t.Fatal("rows1", err)
|
||||
}
|
||||
defer rows1.Close()
|
||||
|
||||
rows2, err := stmt.QueryContext(ctx)
|
||||
if err != nil {
|
||||
t.Fatal("rows2", err)
|
||||
}
|
||||
defer rows2.Close()
|
||||
|
||||
if rows1.dc != rows2.dc {
|
||||
t.Fatal("stmt prepared on Conn does not use same connection")
|
||||
}
|
||||
}
|
||||
|
||||
func TestConcurrency(t *testing.T) {
|
||||
doConcurrentTest(t, new(concurrentDBQueryTest))
|
||||
doConcurrentTest(t, new(concurrentDBExecTest))
|
||||
doConcurrentTest(t, new(concurrentStmtQueryTest))
|
||||
doConcurrentTest(t, new(concurrentStmtExecTest))
|
||||
doConcurrentTest(t, new(concurrentTxQueryTest))
|
||||
doConcurrentTest(t, new(concurrentTxExecTest))
|
||||
doConcurrentTest(t, new(concurrentTxStmtQueryTest))
|
||||
doConcurrentTest(t, new(concurrentTxStmtExecTest))
|
||||
doConcurrentTest(t, new(concurrentRandomTest))
|
||||
list := []struct {
|
||||
name string
|
||||
ct concurrentTest
|
||||
}{
|
||||
{"Query", new(concurrentDBQueryTest)},
|
||||
{"Exec", new(concurrentDBExecTest)},
|
||||
{"StmtQuery", new(concurrentStmtQueryTest)},
|
||||
{"StmtExec", new(concurrentStmtExecTest)},
|
||||
{"TxQuery", new(concurrentTxQueryTest)},
|
||||
{"TxExec", new(concurrentTxExecTest)},
|
||||
{"TxStmtQuery", new(concurrentTxStmtQueryTest)},
|
||||
{"TxStmtExec", new(concurrentTxStmtExecTest)},
|
||||
{"Random", new(concurrentRandomTest)},
|
||||
}
|
||||
for _, item := range list {
|
||||
t.Run(item.name, func(t *testing.T) {
|
||||
doConcurrentTest(t, item.ct)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestConnectionLeak(t *testing.T) {
|
||||
|
@ -2874,6 +3341,131 @@ func TestConnectionLeak(t *testing.T) {
|
|||
wg.Wait()
|
||||
}
|
||||
|
||||
type nvcDriver struct {
|
||||
fakeDriver
|
||||
skipNamedValueCheck bool
|
||||
}
|
||||
|
||||
func (d *nvcDriver) Open(dsn string) (driver.Conn, error) {
|
||||
c, err := d.fakeDriver.Open(dsn)
|
||||
fc := c.(*fakeConn)
|
||||
fc.db.allowAny = true
|
||||
return &nvcConn{fc, d.skipNamedValueCheck}, err
|
||||
}
|
||||
|
||||
type nvcConn struct {
|
||||
*fakeConn
|
||||
skipNamedValueCheck bool
|
||||
}
|
||||
|
||||
type decimal struct {
|
||||
value int
|
||||
}
|
||||
|
||||
type doNotInclude struct{}
|
||||
|
||||
var _ driver.NamedValueChecker = &nvcConn{}
|
||||
|
||||
func (c *nvcConn) CheckNamedValue(nv *driver.NamedValue) error {
|
||||
if c.skipNamedValueCheck {
|
||||
return driver.ErrSkip
|
||||
}
|
||||
switch v := nv.Value.(type) {
|
||||
default:
|
||||
return driver.ErrSkip
|
||||
case Out:
|
||||
switch ov := v.Dest.(type) {
|
||||
default:
|
||||
return errors.New("unkown NameValueCheck OUTPUT type")
|
||||
case *string:
|
||||
*ov = "from-server"
|
||||
nv.Value = "OUT:*string"
|
||||
}
|
||||
return nil
|
||||
case decimal, []int64:
|
||||
return nil
|
||||
case doNotInclude:
|
||||
return driver.ErrRemoveArgument
|
||||
}
|
||||
}
|
||||
|
||||
func TestNamedValueChecker(t *testing.T) {
|
||||
Register("NamedValueCheck", &nvcDriver{})
|
||||
db, err := Open("NamedValueCheck", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
_, err = db.ExecContext(ctx, "WIPE")
|
||||
if err != nil {
|
||||
t.Fatal("exec wipe", err)
|
||||
}
|
||||
|
||||
_, err = db.ExecContext(ctx, "CREATE|keys|dec1=any,str1=string,out1=string,array1=any")
|
||||
if err != nil {
|
||||
t.Fatal("exec create", err)
|
||||
}
|
||||
|
||||
o1 := ""
|
||||
_, err = db.ExecContext(ctx, "INSERT|keys|dec1=?A,str1=?,out1=?O1,array1=?", Named("A", decimal{123}), "hello", Named("O1", Out{Dest: &o1}), []int64{42, 128, 707}, doNotInclude{})
|
||||
if err != nil {
|
||||
t.Fatal("exec insert", err)
|
||||
}
|
||||
var (
|
||||
str1 string
|
||||
dec1 decimal
|
||||
arr1 []int64
|
||||
)
|
||||
err = db.QueryRowContext(ctx, "SELECT|keys|dec1,str1,array1|").Scan(&dec1, &str1, &arr1)
|
||||
if err != nil {
|
||||
t.Fatal("select", err)
|
||||
}
|
||||
|
||||
list := []struct{ got, want interface{} }{
|
||||
{o1, "from-server"},
|
||||
{dec1, decimal{123}},
|
||||
{str1, "hello"},
|
||||
{arr1, []int64{42, 128, 707}},
|
||||
}
|
||||
|
||||
for index, item := range list {
|
||||
if !reflect.DeepEqual(item.got, item.want) {
|
||||
t.Errorf("got %#v wanted %#v for index %d", item.got, item.want, index)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestNamedValueCheckerSkip(t *testing.T) {
|
||||
Register("NamedValueCheckSkip", &nvcDriver{skipNamedValueCheck: true})
|
||||
db, err := Open("NamedValueCheckSkip", "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer db.Close()
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel()
|
||||
|
||||
_, err = db.ExecContext(ctx, "WIPE")
|
||||
if err != nil {
|
||||
t.Fatal("exec wipe", err)
|
||||
}
|
||||
|
||||
_, err = db.ExecContext(ctx, "CREATE|keys|dec1=any")
|
||||
if err != nil {
|
||||
t.Fatal("exec create", err)
|
||||
}
|
||||
|
||||
_, err = db.ExecContext(ctx, "INSERT|keys|dec1=?A", Named("A", decimal{123}))
|
||||
if err == nil {
|
||||
t.Fatalf("expected error with bad argument, got %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// badConn implements a bad driver.Conn, for TestBadDriver.
|
||||
// The Exec method panics.
|
||||
type badConn struct{}
|
||||
|
@ -2965,6 +3557,24 @@ func TestPing(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Issue 18101.
|
||||
func TestTypedString(t *testing.T) {
|
||||
db := newTestDB(t, "people")
|
||||
defer closeDB(t, db)
|
||||
|
||||
type Str string
|
||||
var scanned Str
|
||||
|
||||
err := db.QueryRow("SELECT|people|name|name=?", "Alice").Scan(&scanned)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
expected := Str("Alice")
|
||||
if scanned != expected {
|
||||
t.Errorf("expected %+v, got %+v", expected, scanned)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConcurrentDBExec(b *testing.B) {
|
||||
b.ReportAllocs()
|
||||
ct := new(concurrentDBExecTest)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue