InTx performs database operations inside a transaction.
(function func(Store) error, txOpts *sql.TxOptions)
| 183 | |
| 184 | // InTx performs database operations inside a transaction. |
| 185 | func (q *sqlQuerier) runTx(function func(Store) error, txOpts *sql.TxOptions) (err error) { |
| 186 | if _, ok := q.db.(*sqlx.Tx); ok { |
| 187 | // If the current inner "db" is already a transaction, we just reuse it. |
| 188 | // We do not need to handle commit/rollback as the outer tx will handle |
| 189 | // that. |
| 190 | err := function(q) |
| 191 | if err != nil { |
| 192 | return xerrors.Errorf("execute transaction: %w", err) |
| 193 | } |
| 194 | return nil |
| 195 | } |
| 196 | |
| 197 | transaction, err := q.sdb.BeginTxx(context.Background(), txOpts) |
| 198 | if err != nil { |
| 199 | return xerrors.Errorf("begin transaction: %w", err) |
| 200 | } |
| 201 | defer func() { |
| 202 | rerr := transaction.Rollback() |
| 203 | if rerr == nil || errors.Is(rerr, sql.ErrTxDone) { |
| 204 | // no need to do anything, tx committed successfully |
| 205 | return |
| 206 | } |
| 207 | // couldn't roll back for some reason, extend returned error |
| 208 | err = xerrors.Errorf("defer (%s): %w", rerr.Error(), err) |
| 209 | }() |
| 210 | err = function(&sqlQuerier{db: transaction}) |
| 211 | if err != nil { |
| 212 | return xerrors.Errorf("execute transaction: %w", err) |
| 213 | } |
| 214 | err = transaction.Commit() |
| 215 | if err != nil { |
| 216 | return xerrors.Errorf("commit transaction: %w", err) |
| 217 | } |
| 218 | return nil |
| 219 | } |
| 220 | |
| 221 | func safeString(s *string) string { |
| 222 | if s == nil { |