lib/pg_conn.rb in pg_conn-0.15.0 vs lib/pg_conn.rb in pg_conn-0.15.1
- old
+ new
@@ -65,11 +65,14 @@
# The transaction timestamp of the most recent SQL statement executed by
# #exec or #transaction block
attr_reader :timestamp
- # PG::Error object if the last statement failed; otherwise nil
+ # PG::Error object of the first failed statement in the transaction;
+ # otherwise nil. It is cleared at the beginning of a transaction so be sure
+ # to save it before you run any cleanup code that may initiate new
+ # transactions
attr_reader :error
# Tuple of error message, lineno, and charno of the error object where each
# element defaults to nil if not found
def err
@@ -605,28 +608,21 @@
# error state and if you're also using subtransactions the whole
# transaction stack has collapsed
#
# TODO: Make sure the transaction stack is emptied on postgres errors
def exec(sql, commit: true, fail: true, silent: false)
- begin
- transaction(commit: commit) { execute(sql, fail: fail, silent: silent) }
- rescue PG::Error
- raise if fail
- cancel_transaction
- return nil
- end
+ transaction(commit: commit) { execute(sql, fail: fail, silent: silent) }
end
# Like #exec but returns true/false depending on if the command succeeded.
- # There is not corresponding #exeucte? method because any failure rolls
+ # There is not a corresponding #execute? method because any failure rolls
# back the whole transaction stack. TODO: Check which exceptions that
# should be captured
def exec?(sql, commit: true, silent: true)
begin
exec(sql, commit: commit, fail: true, silent: silent)
rescue PG::Error
- cancel_transaction
return false
end
return true
end
@@ -641,10 +637,11 @@
def execute(sql, fail: true, silent: false)
if @pg_connection
begin
pg_exec(sql, silent: silent)&.cmd_tuples
rescue PG::Error
+ cancel_transaction
raise if fail
return nil
end
else
pg_exec(sql, silent: silent)
@@ -670,23 +667,30 @@
# TODO: Move to TransactionMethods
def commit()
if transaction?
- pop_transaction
+ pop_transaction(fail: false)
else
pg_exec("commit")
end
end
def rollback() raise Rollback end
- # True if a transaction is in progress. Note that this requires all
- # transactions to be started using PgConn's transaction methods;
- # transactions started using raw SQL are not registered
+ # True if a transaction is in progress
+ #
+ # Note that this requires all transactions to be started using PgConn's
+ # transaction methods; transactions started using raw SQL are not
+ # registered
def transaction?() !@savepoints.nil? end
+ # True if a database transaction is in progress
+ def database_transaction?
+ pg_exec("select transaction_timestamp() != statement_timestamp()", fail: false)
+ end
+
# Returns number of transaction or savepoint levels
def transactions() @savepoints ? 1 + @savepoints.size : 0 end
def push_transaction
if transaction?
@@ -694,15 +698,16 @@
@savepoints.push savepoint
pg_exec("savepoint #{savepoint}")
else
@savepoints = []
pg_exec("begin")
+ @error = @err = nil
@timestamp = pg_exec("select current_timestamp").values[0][0] if @pg_connection
end
end
- def pop_transaction(commit: true, fail: true)
+ def pop_transaction(commit: true, fail: true, exception: true)
if transaction?
if savepoint = @savepoints.pop
if !commit
pg_exec("rollback to savepoint #{savepoint}")
pg_exec("release savepoint #{savepoint}")
@@ -726,12 +731,14 @@
# progress, the method always succeeds
def cancel_transaction
begin
pg_exec("rollback")
rescue PG::Error
+ ;
end
@savepoints = nil
+ true
end
# Start a transaction. If called with a block, the block is executed within
# a transaction that is auto-committed if the commit option is true (the
# default). #transaction returns the result of the block or nil if no block
@@ -746,17 +753,18 @@
result = nil
begin
push_transaction
result = yield
rescue PgConn::Rollback
- pop_transaction(commit: false)
+ pop_transaction(commit: false, fail: false)
return nil
rescue PG::Error
+ cancel_transaction
@savepoints = nil
raise
end
- pop_transaction(commit: commit)
+ pop_transaction(commit: commit, fail: false)
result
else
push_transaction
nil
end
@@ -810,11 +818,10 @@
# though
#
# TODO: Fix silent by not handling exceptions
def pg_exec(arg, silent: false)
if @pg_connection
- @error = @err = nil
begin
last_stmt = nil # To make the current SQL statement visible to the rescue clause. FIXME Not used?
if arg.is_a?(String)
return nil if arg == ""
last_stmt = arg
@@ -824,12 +831,14 @@
return nil if stmts.empty?
# stmts.unshift("set on_error_exit stop")
last_stmt = stmts.last
@pg_connection.exec(stmts.join(";\n"))
end
-
rescue PG::Error => ex
- @error = ex
+ if @error.nil?
+ @error = ex
+ @err = nil
+ end
if !silent # FIXME Why do we handle this?
$stderr.puts arg
$stderr.puts
$stderr.puts ex.message
$stderr.flush