@@ -314,6 +314,184 @@ func TestIsolationLevelAutoCommit(t *testing.T) {
314314 }
315315}
316316
317+ func TestDefaultReadLockMode (t * testing.T ) {
318+ t .Parallel ()
319+
320+ for mode , name := range spannerpb .TransactionOptions_ReadWrite_ReadLockMode_name {
321+ readLockMode := spannerpb .TransactionOptions_ReadWrite_ReadLockMode (mode )
322+ db , server , teardown := setupTestDBConnectionWithParams (t , fmt .Sprintf ("read_lock_mode=%v" , name ))
323+ defer teardown ()
324+ ctx := context .Background ()
325+
326+ c , err := db .Conn (ctx )
327+ if err != nil {
328+ t .Fatal (err )
329+ }
330+ if err := c .Raw (func (driverConn interface {}) error {
331+ spannerConn , ok := driverConn .(* conn )
332+ if ! ok {
333+ return fmt .Errorf ("expected spanner conn, got %T" , driverConn )
334+ }
335+ if spannerConn .ReadLockMode () != readLockMode {
336+ return fmt .Errorf ("expected read lock mode %v, got %v" , readLockMode , spannerConn .ReadLockMode ())
337+ }
338+ return nil
339+ }); err != nil {
340+ t .Fatal (err )
341+ }
342+
343+ tx , _ := db .BeginTx (ctx , & sql.TxOptions {})
344+ _ , _ = tx .ExecContext (ctx , testutil .UpdateBarSetFoo )
345+ _ = tx .Rollback ()
346+
347+ requests := drainRequestsFromServer (server .TestSpanner )
348+ beginRequests := requestsOfType (requests , reflect .TypeOf (& spannerpb.BeginTransactionRequest {}))
349+ if g , w := len (beginRequests ), 0 ; g != w {
350+ t .Fatalf ("begin requests count mismatch\n Got: %v\n Want: %v" , g , w )
351+ }
352+ executeRequests := requestsOfType (requests , reflect .TypeOf (& spannerpb.ExecuteSqlRequest {}))
353+ if g , w := len (executeRequests ), 1 ; g != w {
354+ t .Fatalf ("execute requests count mismatch\n Got: %v\n Want: %v" , g , w )
355+ }
356+ request := executeRequests [0 ].(* spannerpb.ExecuteSqlRequest )
357+ if request .GetTransaction () == nil || request .GetTransaction ().GetBegin () == nil {
358+ t .Fatalf ("ExecuteSqlRequest should have a Begin transaction" )
359+ }
360+ if g , w := request .GetTransaction ().GetBegin ().GetReadWrite ().GetReadLockMode (), readLockMode ; g != w {
361+ t .Fatalf ("begin read lock mode mismatch\n Got: %v\n Want: %v" , g , w )
362+ }
363+ }
364+ }
365+
366+ func TestSetReadLockMode (t * testing.T ) {
367+ t .Parallel ()
368+
369+ db , _ , teardown := setupTestDBConnection (t )
370+ defer teardown ()
371+ ctx := context .Background ()
372+
373+ // Repeat twice to ensure that the state is reset after closing the connection.
374+ for i := 0 ; i < 2 ; i ++ {
375+ c , err := db .Conn (ctx )
376+ if err != nil {
377+ t .Fatal (err )
378+ }
379+ var readLockMode spannerpb.TransactionOptions_ReadWrite_ReadLockMode
380+ _ = c .Raw (func (driverConn interface {}) error {
381+ readLockMode = driverConn .(* conn ).ReadLockMode ()
382+ return nil
383+ })
384+ if g , w := readLockMode , spannerpb .TransactionOptions_ReadWrite_READ_LOCK_MODE_UNSPECIFIED ; g != w {
385+ t .Fatalf ("read lock mode mismatch\n Got: %v\n Want: %v" , g , w )
386+ }
387+ _ = c .Raw (func (driverConn interface {}) error {
388+ return driverConn .(SpannerConn ).SetReadLockMode (spannerpb .TransactionOptions_ReadWrite_OPTIMISTIC )
389+ })
390+ _ = c .Raw (func (driverConn interface {}) error {
391+ readLockMode = driverConn .(SpannerConn ).ReadLockMode ()
392+ return nil
393+ })
394+ if g , w := readLockMode , spannerpb .TransactionOptions_ReadWrite_OPTIMISTIC ; g != w {
395+ t .Fatalf ("read lock mode mismatch\n Got: %v\n Want: %v" , g , w )
396+ }
397+ _ = c .Close ()
398+ }
399+ }
400+
401+ func TestReadLockModeAutoCommit (t * testing.T ) {
402+ t .Parallel ()
403+
404+ db , server , teardown := setupTestDBConnection (t )
405+ defer teardown ()
406+ ctx := context .Background ()
407+
408+ for mode := range spannerpb .TransactionOptions_ReadWrite_ReadLockMode_name {
409+ readLockMode := spannerpb .TransactionOptions_ReadWrite_ReadLockMode (mode )
410+ _ , _ = db .ExecContext (ctx , testutil .UpdateBarSetFoo , ExecOptions {TransactionOptions : spanner.TransactionOptions {
411+ ReadLockMode : readLockMode ,
412+ }})
413+
414+ requests := drainRequestsFromServer (server .TestSpanner )
415+ executeRequests := requestsOfType (requests , reflect .TypeOf (& spannerpb.ExecuteSqlRequest {}))
416+ if g , w := len (executeRequests ), 1 ; g != w {
417+ t .Fatalf ("execute requests count mismatch\n Got: %v\n Want: %v" , g , w )
418+ }
419+ request := executeRequests [0 ].(* spannerpb.ExecuteSqlRequest )
420+ if g , w := request .Transaction .GetBegin ().GetReadWrite ().GetReadLockMode (), readLockMode ; g != w {
421+ t .Fatalf ("begin read lock mode mismatch\n Got: %v\n Want: %v" , g , w )
422+ }
423+ }
424+ }
425+
426+ func TestSetLocalReadLockMode (t * testing.T ) {
427+ t .Parallel ()
428+
429+ db , server , teardown := setupTestDBConnection (t )
430+ // Make sure we only have one connection in the pool.
431+ db .SetMaxOpenConns (1 )
432+ defer teardown ()
433+ ctx := context .Background ()
434+
435+ tx , err := db .BeginTx (ctx , nil )
436+ if err != nil {
437+ t .Fatal (err )
438+ }
439+ if _ , err := tx .ExecContext (ctx , "set local read_lock_mode='optimistic'" ); err != nil {
440+ t .Fatal (err )
441+ }
442+ if _ , err := tx .ExecContext (ctx , testutil .UpdateBarSetFoo ); err != nil {
443+ t .Fatal (err )
444+ }
445+ if err := tx .Commit (); err != nil {
446+ t .Fatal (err )
447+ }
448+
449+ requests := drainRequestsFromServer (server .TestSpanner )
450+ beginRequests := requestsOfType (requests , reflect .TypeOf (& spannerpb.BeginTransactionRequest {}))
451+ if g , w := len (beginRequests ), 0 ; g != w {
452+ t .Fatalf ("begin requests count mismatch\n Got: %v\n Want: %v" , g , w )
453+ }
454+ executeRequests := requestsOfType (requests , reflect .TypeOf (& spannerpb.ExecuteSqlRequest {}))
455+ if g , w := len (executeRequests ), 1 ; g != w {
456+ t .Fatalf ("execute requests count mismatch\n Got: %v\n Want: %v" , g , w )
457+ }
458+ request := executeRequests [0 ].(* spannerpb.ExecuteSqlRequest )
459+ if request .GetTransaction () == nil || request .GetTransaction ().GetBegin () == nil {
460+ t .Fatalf ("ExecuteSqlRequest should have a Begin transaction" )
461+ }
462+ if g , w := request .GetTransaction ().GetBegin ().GetReadWrite ().GetReadLockMode (), spannerpb .TransactionOptions_ReadWrite_OPTIMISTIC ; g != w {
463+ t .Fatalf ("begin read lock mode mismatch\n Got: %v\n Want: %v" , g , w )
464+ }
465+
466+ // Execute another transaction without a specific read lock mode. This should then use the default.
467+ tx , err = db .BeginTx (ctx , nil )
468+ if err != nil {
469+ t .Fatal (err )
470+ }
471+ if _ , err := tx .ExecContext (ctx , testutil .UpdateBarSetFoo ); err != nil {
472+ t .Fatal (err )
473+ }
474+ if err := tx .Commit (); err != nil {
475+ t .Fatal (err )
476+ }
477+ requests = drainRequestsFromServer (server .TestSpanner )
478+ beginRequests = requestsOfType (requests , reflect .TypeOf (& spannerpb.BeginTransactionRequest {}))
479+ if g , w := len (beginRequests ), 0 ; g != w {
480+ t .Fatalf ("begin requests count mismatch\n Got: %v\n Want: %v" , g , w )
481+ }
482+ executeRequests = requestsOfType (requests , reflect .TypeOf (& spannerpb.ExecuteSqlRequest {}))
483+ if g , w := len (executeRequests ), 1 ; g != w {
484+ t .Fatalf ("execute requests count mismatch\n Got: %v\n Want: %v" , g , w )
485+ }
486+ request = executeRequests [0 ].(* spannerpb.ExecuteSqlRequest )
487+ if request .GetTransaction () == nil || request .GetTransaction ().GetBegin () == nil {
488+ t .Fatalf ("ExecuteSqlRequest should have a Begin transaction" )
489+ }
490+ if g , w := request .GetTransaction ().GetBegin ().GetReadWrite ().GetReadLockMode (), spannerpb .TransactionOptions_ReadWrite_READ_LOCK_MODE_UNSPECIFIED ; g != w {
491+ t .Fatalf ("begin read lock mode mismatch\n Got: %v\n Want: %v" , g , w )
492+ }
493+ }
494+
317495func TestCreateDatabase (t * testing.T ) {
318496 t .Parallel ()
319497
0 commit comments