Skip to content

Commit

Permalink
Merge pull request #110 from bborgesr/dbWithTransaction
Browse files Browse the repository at this point in the history
- New `dbWithTransaction()` that calls `dbBegin()` and `dbCommit()`, and `dbRollback()` on failure (#110, @bborgesr).
  • Loading branch information
krlmlr authored Jun 14, 2016
2 parents 5213bf6 + 8724524 commit a1367f7
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 2 deletions.
2 changes: 2 additions & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export(dbRollback)
export(dbSendQuery)
export(dbSetDataMappings)
export(dbUnloadDriver)
export(dbWithTransaction)
export(dbWriteTable)
export(fetch)
export(isSQLKeyword)
Expand Down Expand Up @@ -65,6 +66,7 @@ exportMethods(dbDataType)
exportMethods(dbExecute)
exportMethods(dbGetQuery)
exportMethods(dbQuoteIdentifier)
exportMethods(dbWithTransaction)
exportMethods(show)
exportMethods(sqlAppendTable)
exportMethods(sqlCreateTable)
Expand Down
3 changes: 1 addition & 2 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
# DBI 0.4-2 (2016-06-08)

- Remove redundant declaration of transaction methods (#110, @@bborgesr).
- Remove redundant declaration of transaction methods (#110, @bborgesr).
- New `dbExecute()`, forwards to `dbSendQuery()` by default (#109, @bborgesr).


# DBI 0.4-1 (2016-05-07)

- The default `show()` implementations silently ignore all errors. Some DBI drivers (e.g., RPostgreSQL) might fail to implement `dbIsValid()` or the other methods used.
Expand Down
72 changes: 72 additions & 0 deletions R/transactions.R
Original file line number Diff line number Diff line change
Expand Up @@ -44,3 +44,75 @@ setGeneric("dbRollback",
def = function(conn, ...) standardGeneric("dbRollback"),
valueClass = "logical"
)

#' Self-contained SQL transactions.
#'
#' Given that \code{\link{transactions}} are implemented, then this function
#' allows you pass in code that is treated as a transaction. The advantage is
#' that you don't have to remember to do \code{dbBegin} and \code{dbCommit} or
#' \code{dbRollback} -- that is all taken care of.
#'
#' @section Side Effects:
#' The transaction in \code{code} on the connection \code{conn} is committed
#' or rolled back. The \code{code} chunk may also also modify the local R
#' environment.
#'
#' @param conn A \code{\linkS4class{DBIConnection}} object, as produced by
#' \code{\link{dbConnect}}.
#' @param code An arbitrary block of R code
#'
#' @return The result of the evaluation of \code{code}
#' @aliases dbWithTransaction,DBIConnection-method
#' @export
#' @examples
#' con <- dbConnect(RSQLite::SQLite(), ":memory:")
#' dbWriteTable(con, "cars", head(cars, 3))
#' dbReadTable(con, "cars") # there's 3 rows!
#' ## successful transaction
#' dbWithTransaction(con, {
#' dbExecute(con, "INSERT INTO cars (speed, dist) VALUES (1, 1);")
#' dbExecute(con, "INSERT INTO cars (speed, dist) VALUES (2, 2);")
#' dbExecute(con, "INSERT INTO cars (speed, dist) VALUES (3, 3);")
#' })
#' dbReadTable(con, "cars") # there's now 6 rows!
#'
#' \dontrun{
#' ## unsuccessful transaction -- note the missing comma
#' dbWithTransaction(con,{
#' dbExecute(con, "INSERT INTO cars (speed, dist) VALUES (1, 1);")
#' dbExecute(con, "INSERT INTO cars (speed dist) VALUES (2, 2);")
#' dbExecute(con, "INSERT INTO cars (speed, dist) VALUES (3, 3);")
#' })
#' dbReadTable(con, "cars") # nothing was changed
#' }
#' dbDisconnect(con)
setGeneric("dbWithTransaction",
def = function(conn, code) standardGeneric("dbWithTransaction")
)

#' @export
setMethod("dbWithTransaction", "DBIConnection", function(conn, code) {
## check if each operation is successful
call <- dbBegin(conn)
if (identical(call, FALSE)) {
stop("Failed to begin transaction", call. = FALSE)
}
tryCatch({
res <- force(code)
call <- dbCommit(conn)
if (identical(call, FALSE)) {
stop("Failed to commit transaction", call. = FALSE)
}
res
},
error = function(e) {
call <- dbRollback(conn)
if (identical(call, FALSE)) {
stop(paste("Failed to rollback transaction.",
"Tried to roll back because an error",
"occurred:", conditionMessage(e)),
call. = FALSE)
}
stop(e)
})
})
54 changes: 54 additions & 0 deletions man/dbWithTransaction.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit a1367f7

Please sign in to comment.