DBI:Pg 'autocommit' is not a valid option name

I’m trying to use transactions with DBI and PostgreSQL and I’m running
into problems. I’m using ruby-dbi 0.0.17 and PostgreSQL 7.2.3 (latest
Debian unstable package).

The first problem is that I can’t convince Pg to switch autocommit mode
off. All I get is “‘autocommit’ is not a valid option name”, no matter
if I do it via DBI or in psql. From this follows the second problem:
DatabaseHandle#transaction doesn’t work as is and I need to add explict
BEGIN/END statements:

DBI.connect(dbrc.dsn, dbrc.user, dbrc.password) do |dbh|
dbh.transaction do |dbh|
dbh.do "BEGIN"
dbh.do "INSERT …"
raise "Don’t commit!!!"
dbh.do "END"
end
end

This is the first time I’m playing with DBI and I’m a Pg newbie, too.
So take the following with a shovel of salt.

I propose to change dbi.rb in the following way

class DatabaseHandle

def transaction
raise InterfaceError, “Database connection was already closed!” if
@handle.nil?
raise InterfaceError, “No block given” unless block_given?

commit
begin_transaction
begin
  yield self
  commit
  end_transaction
rescue Exception
  rollback
  end_transaction
  raise
end

end

def begin_transaction
@handle.begin_transaction
end

def end_transaction
@handle.end_transaction
end

end

class BaseDatabase
def start_transaction
raise NotSupportedError
end
def end_transaction
raise NotSupportedError
end
end

And change Pg.rb in the following way

class Database
def start_transaction
@connection.exec(“BEGIN”)
end
def end_transaction
@connection.exec(“END”)
end
end

Possibly these methods need to (or should) take into account the state
of AutoCommit.

Michael

···


Michael Schuerig If at first you don’t succeed…
mailto:schuerig@acm.org try, try again.
http://www.schuerig.de/michael/ --Jerome Morrow, “Gattaca”

The first problem is that I can’t convince Pg to switch autocommit mode
off. All I get is “‘autocommit’ is not a valid option name”, no matter
if I do it via DBI or in psql.

This works for me with DBI …

dbh['AutoCommit'] = false

DatabaseHandle#transaction doesn’t work as is and I need to add explict
BEGIN/END statements:

DBI.connect(dbrc.dsn, dbrc.user, dbrc.password) do |dbh|
dbh.transaction do |dbh|
dbh.do “BEGIN”
dbh.do “INSERT …”
raise “Don’t commit!!!”
dbh.do “END”
end
end

Interesting … I ran into a similar problem just today. I wasn’t using
the Pg DBD, so details might be different.

The key is that when the DB handle is in auto-commit mode, it will not
automatically insert the BEGIN/END statements. The transaction method
should (but doesn’t) disable auto-commit internally.

My work around was to do this …

def f(db)
ac = db[‘AutoCommit’]
db[‘AutoCommit’] = false
db.transaction {
# … do database stuff …
}
ensure
db[‘AutoCommit’] = ac
end

Of course, this could be refactored into a alternate version of
transaction where the “do database stuff” is a yield.

This is the first time I’m playing with DBI and I’m a Pg newbie, too.
So take the following with a shovel of salt.

I propose to change dbi.rb in the following way

[… proposed changes to DBI elided …]

Possibly these methods need to (or should) take into account the state
of AutoCommit.

Its been a while since I looked at the Pg DBD driver, but it might be
enough to turn off auto-commit during the transaction. But I agree with
the general premise that “transaction” should work whatever the state of
auto-commit.

···

On Wed, 2002-10-16 at 19:05, Michael Schuerig wrote:


– Jim Weirich jweirich@one.net http://w3.one.net/~jweirich

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Jim Weirich wrote:

The first problem is that I can’t convince Pg to switch autocommit
mode off. All I get is “‘autocommit’ is not a valid option name”, no
matter if I do it via DBI or in psql.

This works for me with DBI …

dbh['AutoCommit'] = false

Doesn’t work for me, although I’m sure it should. I have no idea what’s
going wrong.

The key is that when the DB handle is in auto-commit mode, it will not
automatically insert the BEGIN/END statements. The transaction method
should (but doesn’t) disable auto-commit internally.

My work around was to do this …

def f(db)
ac = db[‘AutoCommit’]
db[‘AutoCommit’] = false
db.transaction {
# … do database stuff …
}
ensure
db[‘AutoCommit’] = ac
end

Alternatively, the same could be done elegantly with more general
version of fluid by Brian Marick:

def f(db)
  Fluid.let(["db['AutoCommit']", false]) {
    db.transaction {
      # ... do database stuff ...
    }
  }
end

As it is, the code above does not work. The general intention of
Fluid.let is to change the value of a global variable for the duration
of a block. I’d really like to see a facility for this in the standard
lib.

Michael

···

On Wed, 2002-10-16 at 19:05, Michael Schuerig wrote:


Michael Schuerig If at first you don’t succeed…
mailto:schuerig@acm.org try, try again.
Michael Schürig | Sentenced to making sense --Jerome Morrow, “Gattaca”

Jim Weirich wrote:

This works for me with DBI …
dbh[‘AutoCommit’] = false

Doesn’t work for me, although I’m sure it should. I have no idea what’s
going wrong.

Here’s the full script. This one was written against the Pg DBD. When
the “fail” is triggered, the INSERT will be rolled back, as expected.

#!/usr/bin/env ruby

require ‘dbi’

db = DBI.connect(“DBI:Pg:junk”, “jim”)

fail “Usage: insert.rb first last” if ARGV.size != 2
first, last = ARGV

begin
db[‘AutoCommit’] = false
db.transaction {
db.do (“INSERT INTO people(first, last) VALUES (?,?)”, first, last)
fail if first == “John”
}
rescue RuntimeError => ex
puts “Got Exception: #{ex}”
end
db[‘AutoCommit’] = true

row = db.select_one(
“SELECT first, last FROM people WHERE first = ? AND last = ?”,
first,
last)
if row.nil?
puts “Insert failed”
else
puts “Inserted #{row[0]} #{row[1]}”
end

···

On Thu, 2002-10-17 at 00:05, Michael Schuerig wrote:


– Jim Weirich jweirich@one.net http://w3.one.net/~jweirich

“Beware of bugs in the above code; I have only proved it correct,
not tried it.” – Donald Knuth (in a memo to Peter van Emde Boas)

Jim Weirich wrote:

#!/usr/bin/env ruby

require ‘dbi’

db = DBI.connect(“DBI:Pg:junk”, “jim”)

fail “Usage: insert.rb first last” if ARGV.size != 2
first, last = ARGV

begin
db[‘AutoCommit’] = false

Here’s where it fails with

/usr/local/lib/site_ruby/1.6/DBD/Pg/Pg.rb:253:in `exec’: ERROR:
‘autocommit’ is not a valid option name (PGError)

No idea what’s happening. I’m asking in the PostgreSQL “questions”
group.

Michael

···


Michael Schuerig If at first you don’t succeed…
mailto:schuerig@acm.org try, try again.
Michael Schürig | Sentenced to making sense --Jerome Morrow, “Gattaca”

Try the previous version (0.0.16) of Ruby/DBI until this has been
fixed. Ruby/DBI 0.0.17 differs in the way it handles transactions; it
uses the PostgreSQL command “SET AUTOCOMMIT TO ON|OFF”. But this does
not work as expected and is going to be removed from PostgreSQL.

Regards,

Michael

···

On Thu, 2002-10-17 at 09:06, Michael Schuerig wrote:

Jim Weirich wrote:

#!/usr/bin/env ruby

require ‘dbi’

db = DBI.connect(“DBI:Pg:junk”, “jim”)

fail “Usage: insert.rb first last” if ARGV.size != 2
first, last = ARGV

begin
db[‘AutoCommit’] = false

Here’s where it fails with

/usr/local/lib/site_ruby/1.6/DBD/Pg/Pg.rb:253:in `exec’: ERROR:
‘autocommit’ is not a valid option name (PGError)