Package: libdbi-ruby1.8 Version: 0.4.3-2 Severity: normal Tags: patch
If return is made from within DatabaseHandle#transaction block, commit isn't done. I've attached 2 programs: 1. transaction_return - insert data into the test table (and, optionally, run the second transaction); 2. check - print test table data. $./transaction_return && ./check inserting `100' into public.test 0 rows in public.test Without execution of the second transaction, commit isn't done. $./transaction_return 1 && ./check inserting `100' into public.test executing empty transaction 1 rows in public.test id: 100 When the second transaction is executed, INSERT done in the previous transaction is commited. From this it can be concluded that neither commit nor rollback is done when `return' is executed from within a transaction method block. I'm attaching a patch that ensures that commit happens even if control is transferred out of the transaction method. The patch also enhances transaction method to return value returned by block when it could be used in the calling code (i.e. when no exception happened and no return statement executed). P.S. I've looked at libdbi-ruby source code in Lenny and based on this assume it's also affected. -- System Information: Debian Release: squeeze/sid APT prefers testing APT policy: (500, 'testing') Architecture: i386 (i686) Kernel: Linux 2.6.32-5-686 (SMP w/1 CPU core) Locale: LANG=en_NZ.UTF-8, LC_CTYPE=en_NZ.UTF-8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash Versions of packages libdbi-ruby1.8 depends on: ii libdeprecated-ruby1.8 2.0.1-2 Library for handling deprecated co ii libruby1.8 1.8.7.299-1 Libraries necessary to run Ruby 1. libdbi-ruby1.8 recommends no packages. Versions of packages libdbi-ruby1.8 suggests: ii libdbi-ruby 0.4.3-2 Database Independent Interface for -- no debconf information
#!/usr/bin/ruby require 'dbi' @db = DBI.connect 'DBI:Pg:test', 'postgres' rows = @db.select_all('SELECT * FROM public.test') puts "#{rows.size} rows in public.test" rows.each { |r| puts "id: #{r.first}" }
#!/usr/bin/ruby require 'dbi' second_transaction = $*.first && $*.first == '1' ? true : false @db = DBI.connect 'DBI:Pg:test', 'postgres' @db['AutoCommit'] = false if @db.select_all("SELECT tablename FROM pg_tables " \ "WHERE schemaname = 'public' AND tablename = 'test'").size == 1 @db.do 'DROP TABLE public.test' end @db.do <<EOF CREATE TABLE public.test ( id INTEGER NOT NULL ); EOF def newId(id) @db.transaction { |db| puts "inserting `#{id}' into public.test" db.do('INSERT INTO public.test VALUES($1)', id) return 42 } end newId(100) exit unless second_transaction puts "executing empty transaction" @db.transaction { |db| }
--- database.rb 2010-07-19 19:27:38.000000000 +1200 +++ libdbi-ruby-0.4.3/lib/dbi/handles/database.rb 2010-07-19 19:35:13.000000000 +1200 @@ -208,11 +208,16 @@ commit begin - yield self + ret = yield self commit + done = true + ret rescue Exception rollback + done = true raise + ensure + commit unless done end end