@@ -926,7 +926,10 @@ func (c *conn) execContext(ctx context.Context, query string, execOptions ExecOp
926926func (c * conn ) options (reset bool ) ExecOptions {
927927 if reset {
928928 defer func () {
929- c .execOptions .TransactionOptions .TransactionTag = ""
929+ // Only reset the transaction tag if there is no active transaction on the connection.
930+ if ! c .inTransaction () {
931+ c .execOptions .TransactionOptions .TransactionTag = ""
932+ }
930933 c .execOptions .QueryOptions .RequestTag = ""
931934 }()
932935 }
@@ -958,7 +961,7 @@ func (c *conn) withTempTransactionOptions(options *ReadWriteTransactionOptions)
958961 c .tempTransactionOptions = options
959962}
960963
961- func (c * conn ) getTransactionOptions () ReadWriteTransactionOptions {
964+ func (c * conn ) getTransactionOptions (execOptions ExecOptions ) ReadWriteTransactionOptions {
962965 if c .tempTransactionOptions != nil {
963966 defer func () { c .tempTransactionOptions = nil }()
964967 opts := * c .tempTransactionOptions
@@ -971,7 +974,7 @@ func (c *conn) getTransactionOptions() ReadWriteTransactionOptions {
971974 c .execOptions .TransactionOptions .TransactionTag = ""
972975 }()
973976 txOpts := ReadWriteTransactionOptions {
974- TransactionOptions : c . execOptions .TransactionOptions ,
977+ TransactionOptions : execOptions .TransactionOptions ,
975978 DisableInternalRetries : ! c .RetryAbortsInternally (),
976979 }
977980 // Only use the default isolation level from the connection if the ExecOptions
@@ -1019,7 +1022,7 @@ func (c *conn) Begin() (driver.Tx, error) {
10191022 return c .BeginTx (context .Background (), driver.TxOptions {})
10201023}
10211024
1022- func (c * conn ) BeginTx (ctx context.Context , opts driver.TxOptions ) (driver.Tx , error ) {
1025+ func (c * conn ) BeginTx (ctx context.Context , driverOpts driver.TxOptions ) (driver.Tx , error ) {
10231026 if c .resetForRetry {
10241027 c .resetForRetry = false
10251028 return c .tx , nil
@@ -1033,26 +1036,27 @@ func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, e
10331036
10341037 readOnlyTxOpts := c .getReadOnlyTransactionOptions ()
10351038 batchReadOnlyTxOpts := c .getBatchReadOnlyTransactionOptions ()
1036- readWriteTransactionOptions := c .getTransactionOptions ()
1039+ execOptions := c .execOptions
10371040 if c .inTransaction () {
10381041 return nil , spanner .ToSpannerError (status .Errorf (codes .FailedPrecondition , "already in a transaction" ))
10391042 }
10401043 if c .inBatch () {
10411044 return nil , status .Error (codes .FailedPrecondition , "This connection has an active batch. Run or abort the batch before starting a new transaction." )
10421045 }
10431046
1047+ isolationLevelFromTxOpts := spannerpb .TransactionOptions_ISOLATION_LEVEL_UNSPECIFIED
10441048 // Determine whether internal retries have been disabled using a special
10451049 // value for the transaction isolation level.
10461050 disableRetryAborts := false
10471051 batchReadOnly := false
1048- sil := opts .Isolation >> 8
1049- opts .Isolation = opts .Isolation - sil << 8
1050- if opts .Isolation != driver .IsolationLevel (sql .LevelDefault ) {
1051- level , err := toProtoIsolationLevel (sql .IsolationLevel (opts .Isolation ))
1052+ sil := driverOpts .Isolation >> 8
1053+ driverOpts .Isolation = driverOpts .Isolation - sil << 8
1054+ if driverOpts .Isolation != driver .IsolationLevel (sql .LevelDefault ) {
1055+ level , err := toProtoIsolationLevel (sql .IsolationLevel (driverOpts .Isolation ))
10521056 if err != nil {
10531057 return nil , err
10541058 }
1055- readWriteTransactionOptions . TransactionOptions . IsolationLevel = level
1059+ isolationLevelFromTxOpts = level
10561060 }
10571061 if sil > 0 {
10581062 switch spannerIsolationLevel (sil ) {
@@ -1064,11 +1068,11 @@ func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, e
10641068 // ignore
10651069 }
10661070 }
1067- if batchReadOnly && ! opts .ReadOnly {
1071+ if batchReadOnly && ! driverOpts .ReadOnly {
10681072 return nil , status .Error (codes .InvalidArgument , "levelBatchReadOnly can only be used for read-only transactions" )
10691073 }
10701074
1071- if opts .ReadOnly {
1075+ if driverOpts .ReadOnly {
10721076 var logger * slog.Logger
10731077 var ro * spanner.ReadOnlyTransaction
10741078 var bo * spanner.BatchReadOnlyTransaction
@@ -1106,7 +1110,23 @@ func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, e
11061110 return c .tx , nil
11071111 }
11081112
1109- tx , err := spanner .NewReadWriteStmtBasedTransactionWithOptions (ctx , c .client , readWriteTransactionOptions .TransactionOptions )
1113+ opts := spanner.TransactionOptions {}
1114+ if c .tempTransactionOptions != nil {
1115+ opts = c .tempTransactionOptions .TransactionOptions
1116+ }
1117+ opts .BeginTransactionOption = c .convertDefaultBeginTransactionOption (opts .BeginTransactionOption )
1118+ tempCloseFunc := func () {}
1119+ if c .tempTransactionOptions != nil && c .tempTransactionOptions .close != nil {
1120+ tempCloseFunc = c .tempTransactionOptions .close
1121+ }
1122+ disableInternalRetries := ! c .RetryAbortsInternally ()
1123+ if c .tempTransactionOptions != nil {
1124+ disableInternalRetries = c .tempTransactionOptions .DisableInternalRetries
1125+ }
1126+
1127+ tx , err := spanner .NewReadWriteStmtBasedTransactionWithCallbackForOptions (ctx , c .client , opts , func () spanner.TransactionOptions {
1128+ return c .effectiveTransactionOptions (isolationLevelFromTxOpts , execOptions )
1129+ })
11101130 if err != nil {
11111131 return nil , err
11121132 }
@@ -1117,9 +1137,7 @@ func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, e
11171137 logger : logger ,
11181138 rwTx : tx ,
11191139 close : func (result txResult , commitResponse * spanner.CommitResponse , commitErr error ) {
1120- if readWriteTransactionOptions .close != nil {
1121- readWriteTransactionOptions .close ()
1122- }
1140+ tempCloseFunc ()
11231141 c .prevTx = c .tx
11241142 c .tx = nil
11251143 if commitErr == nil {
@@ -1134,12 +1152,21 @@ func (c *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, e
11341152 }
11351153 },
11361154 // Disable internal retries if any of these options have been set.
1137- retryAborts : ! readWriteTransactionOptions . DisableInternalRetries && ! disableRetryAborts ,
1155+ retryAborts : ! disableInternalRetries && ! disableRetryAborts ,
11381156 }
11391157 c .commitResponse = nil
11401158 return c .tx , nil
11411159}
11421160
1161+ func (c * conn ) effectiveTransactionOptions (isolationLevelFromTxOpts spannerpb.TransactionOptions_IsolationLevel , execOptions ExecOptions ) spanner.TransactionOptions {
1162+ readWriteTransactionOptions := c .getTransactionOptions (execOptions )
1163+ res := readWriteTransactionOptions .TransactionOptions
1164+ if isolationLevelFromTxOpts != spannerpb .TransactionOptions_ISOLATION_LEVEL_UNSPECIFIED {
1165+ res .IsolationLevel = isolationLevelFromTxOpts
1166+ }
1167+ return res
1168+ }
1169+
11431170func (c * conn ) convertDefaultBeginTransactionOption (opt spanner.BeginTransactionOption ) spanner.BeginTransactionOption {
11441171 if opt == spanner .DefaultBeginTransaction {
11451172 if propertyBeginTransactionOption .GetValueOrDefault (c .state ) == spanner .DefaultBeginTransaction {
0 commit comments