TestRawBytesAreNotModified checks for a race condition that arises when a query context is canceled while a user is calling rows.Scan. This is a more stringent test than the one proposed in https://github.com/golang/go/issues/23519. Here we're explicitly using `sql.RawBytes` to check the contents of
(t *testing.T)
| 3277 | // `sql.RawBytes` to check the contents of our internal buffers are not modified after an implicit |
| 3278 | // call to `Rows.Close`, so Context cancellation should **not** invalidate the backing buffers. |
| 3279 | func TestRawBytesAreNotModified(t *testing.T) { |
| 3280 | const blob = "abcdefghijklmnop" |
| 3281 | const contextRaceIterations = 20 |
| 3282 | const blobSize = defaultBufSize * 3 / 4 // Second row overwrites first row. |
| 3283 | const insertRows = 4 |
| 3284 | |
| 3285 | var sqlBlobs = [2]string{ |
| 3286 | strings.Repeat(blob, blobSize/len(blob)), |
| 3287 | strings.Repeat(strings.ToUpper(blob), blobSize/len(blob)), |
| 3288 | } |
| 3289 | |
| 3290 | runTests(t, dsn, func(dbt *DBTest) { |
| 3291 | dbt.mustExec("CREATE TABLE test (id int, value BLOB) CHARACTER SET utf8") |
| 3292 | for i := range insertRows { |
| 3293 | dbt.mustExec("INSERT INTO test VALUES (?, ?)", i+1, sqlBlobs[i&1]) |
| 3294 | } |
| 3295 | |
| 3296 | for i := range contextRaceIterations { |
| 3297 | func() { |
| 3298 | ctx, cancel := context.WithCancel(context.Background()) |
| 3299 | defer cancel() |
| 3300 | |
| 3301 | rows, err := dbt.db.QueryContext(ctx, `SELECT id, value FROM test`) |
| 3302 | if err != nil { |
| 3303 | dbt.Fatal(err) |
| 3304 | } |
| 3305 | defer rows.Close() |
| 3306 | |
| 3307 | var b int |
| 3308 | var raw sql.RawBytes |
| 3309 | if !rows.Next() { |
| 3310 | dbt.Fatal("expected at least one row") |
| 3311 | } |
| 3312 | if err := rows.Scan(&b, &raw); err != nil { |
| 3313 | dbt.Fatal(err) |
| 3314 | } |
| 3315 | |
| 3316 | before := string(raw) |
| 3317 | // Ensure cancelling the query does not corrupt the contents of `raw` |
| 3318 | cancel() |
| 3319 | time.Sleep(time.Microsecond * 100) |
| 3320 | after := string(raw) |
| 3321 | |
| 3322 | if before != after { |
| 3323 | dbt.Fatalf("the backing storage for sql.RawBytes has been modified (i=%v)", i) |
| 3324 | } |
| 3325 | }() |
| 3326 | } |
| 3327 | }) |
| 3328 | } |
| 3329 | |
| 3330 | var _ driver.DriverContext = &MySQLDriver{} |
| 3331 |