diff --git a/lib/plsql/oci_connection.rb b/lib/plsql/oci_connection.rb index a74cd9d8..cd998c6d 100644 --- a/lib/plsql/oci_connection.rb +++ b/lib/plsql/oci_connection.rb @@ -68,14 +68,16 @@ def exec(sql, *bindvars) class Cursor #:nodoc: include Connection::CursorCommon - # stack of open cursors - @@open_cursors = [] + # stacks of open cursors (for each thread) + def self.open_cursors(thread_id = Thread.current.object_id) + (@@open_cursors ||= Hash.new {|stacks, id| stacks[id] = []})[thread_id] + end attr_reader :raw_cursor def initialize(conn, raw_cursor) @connection = conn @raw_cursor = raw_cursor - @@open_cursors.push self + self.class.open_cursors.push self end def self.new_from_parse(conn, sql) @@ -125,7 +127,7 @@ def close_raw_cursor def close # close all cursors that were created after this one - while (open_cursor = @@open_cursors.pop) && !open_cursor.equal?(self) + while (open_cursor = self.class.open_cursors.pop) && !open_cursor.equal?(self) open_cursor.close_raw_cursor end close_raw_cursor diff --git a/spec/plsql/schema_spec.rb b/spec/plsql/schema_spec.rb index f4bd2eca..9743d5f2 100644 --- a/spec/plsql/schema_spec.rb +++ b/spec/plsql/schema_spec.rb @@ -219,6 +219,15 @@ class TestModel < TestBaseModel plsql.activerecord_class = TestModel plsql.schema_name.should == 'HR' end + + it "should safely close cursors in threaded environment" do + unless defined?(JRuby) + t1 = Thread.new {plsql.dbms_lock.sleep(1)}.tap {|t| t.abort_on_exception = true} + t2 = Thread.new {plsql.dbms_lock.sleep(2)}.tap {|t| t.abort_on_exception = true} + t2.join + end + end + end if defined?(ActiveRecord) describe "DBMS_OUTPUT logging" do