@@ -19,6 +19,7 @@ import (
19
19
"io/ioutil"
20
20
"log"
21
21
"math"
22
+ "math/rand"
22
23
"net"
23
24
"net/url"
24
25
"os"
@@ -2938,3 +2939,57 @@ func TestValuerWithValueReceiverGivenNilValue(t *testing.T) {
2938
2939
// This test will panic on the INSERT if ConvertValue() does not check for typed nil before calling Value()
2939
2940
})
2940
2941
}
2942
+
2943
+ // TestContextCancelQueryWhileScan checks for race conditions that arise when
2944
+ // a query context is canceled while a user is calling rows.Scan(). The code
2945
+ // is based on database/sql TestIssue18429.
2946
+ // See https://github.com/golang/go/issues/23519
2947
+ func TestContextCancelQueryWhileScan (t * testing.T ) {
2948
+ const blob = "0123456789abcdef"
2949
+ const sqlQuery = `SELECT id, value FROM test WHERE SLEEP(?) = 0`
2950
+ const contextRaceIterations = 1000
2951
+ const milliWait = 30
2952
+ const blobSize = 64 * 1024
2953
+ const insertRows = 64
2954
+
2955
+ largeBlob := strings .Repeat (blob , blobSize / len (blob ))
2956
+
2957
+ runTests (t , dsn , func (dbt * DBTest ) {
2958
+ dbt .mustExec ("CREATE TABLE test (id int, value MEDIUMBLOB) CHARACTER SET utf8" )
2959
+ for i := 0 ; i < insertRows ; i ++ {
2960
+ dbt .mustExec ("INSERT INTO test VALUES (?, ?)" , i + 1 , largeBlob )
2961
+ }
2962
+
2963
+ sem := make (chan bool , 20 )
2964
+ var wg sync.WaitGroup
2965
+ for i := 0 ; i < contextRaceIterations ; i ++ {
2966
+ sem <- true
2967
+ wg .Add (1 )
2968
+ go func () {
2969
+ defer func () {
2970
+ <- sem
2971
+ wg .Done ()
2972
+ }()
2973
+ qwait := float64 (time .Duration (rand .Intn (milliWait ))* time .Millisecond ) / float64 (time .Second )
2974
+
2975
+ ctx , cancel := context .WithTimeout (context .Background (), time .Duration (rand .Intn (milliWait ))* time .Millisecond )
2976
+ defer cancel ()
2977
+
2978
+ rows , _ := dbt .db .QueryContext (ctx , sqlQuery , qwait )
2979
+ if rows != nil {
2980
+ var b int
2981
+ var n string
2982
+ for rows .Next () {
2983
+ if rows .Scan (& b , & n ) == nil {
2984
+ if len (n ) != blobSize {
2985
+ t .Fatal ("mismatch in read buffer" )
2986
+ }
2987
+ }
2988
+ }
2989
+ rows .Close ()
2990
+ }
2991
+ }()
2992
+ }
2993
+ wg .Wait ()
2994
+ })
2995
+ }
0 commit comments