aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/CHANGELOG2
-rwxr-xr-xactiverecord/Rakefile6
-rw-r--r--activerecord/install.rb1
-rwxr-xr-xactiverecord/lib/active_record.rb1
-rwxr-xr-xactiverecord/lib/active_record/associations.rb2
-rwxr-xr-xactiverecord/lib/active_record/base.rb6
-rw-r--r--activerecord/lib/active_record/connection_adapters/db2_adapter.rb127
-rwxr-xr-xactiverecord/lib/active_record/fixtures.rb2
-rw-r--r--activerecord/lib/active_record/vendor/db2.rb357
-rwxr-xr-xactiverecord/test/associations_test.rb2
-rwxr-xr-xactiverecord/test/base_test.rb6
-rw-r--r--activerecord/test/connections/native_db2/connection.rb24
-rw-r--r--activerecord/test/fixtures/companies.yml21
-rwxr-xr-xactiverecord/test/fixtures/companies/first_client6
-rwxr-xr-xactiverecord/test/fixtures/companies/first_firm4
-rwxr-xr-xactiverecord/test/fixtures/companies/second_client6
-rw-r--r--activerecord/test/fixtures/courses.yml7
-rw-r--r--activerecord/test/fixtures/courses/java2
-rw-r--r--activerecord/test/fixtures/courses/ruby2
-rw-r--r--activerecord/test/fixtures/customers.yml7
-rw-r--r--activerecord/test/fixtures/customers/david6
-rw-r--r--activerecord/test/fixtures/db_definitions/db2.sql112
-rw-r--r--activerecord/test/fixtures/db_definitions/db22.sql4
-rw-r--r--activerecord/test/fixtures/developers_projects.yml13
-rw-r--r--activerecord/test/fixtures/entrants.yml14
-rw-r--r--activerecord/test/fixtures/entrants/first3
-rw-r--r--activerecord/test/fixtures/entrants/second3
-rw-r--r--activerecord/test/fixtures/entrants/third3
-rw-r--r--activerecord/test/fixtures/movies.yml7
-rw-r--r--activerecord/test/fixtures/movies/first2
-rw-r--r--activerecord/test/fixtures/movies/second2
-rw-r--r--activerecord/test/fixtures/projects.yml7
-rw-r--r--activerecord/test/fixtures/projects/action_controller2
-rw-r--r--activerecord/test/fixtures/projects/active_record2
-rw-r--r--activerecord/test/fixtures/topics.yml21
-rwxr-xr-xactiverecord/test/fixtures/topics/first10
-rwxr-xr-xactiverecord/test/fixtures/topics/second8
37 files changed, 740 insertions, 70 deletions
diff --git a/activerecord/CHANGELOG b/activerecord/CHANGELOG
index eb21ad9be0..6375519fee 100644
--- a/activerecord/CHANGELOG
+++ b/activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Added a db2 adapter that only depends on the Ruby/DB2 bindings (http://raa.ruby-lang.org/project/ruby-db2/) #386 [Maik Schmidt]
+
* Added the final touches to the Microsoft SQL Server adapter by DeLynn Berry that makes it suitable for actual use #394 [DeLynn Barry]
* Fixed a bug in the Ruby/MySQL that caused binary content to be escaped badly and come back mangled #405 [Tobias Luetke]
diff --git a/activerecord/Rakefile b/activerecord/Rakefile
index 30db268556..ef08625e35 100755
--- a/activerecord/Rakefile
+++ b/activerecord/Rakefile
@@ -51,6 +51,12 @@ Rake::TestTask.new("test_sqlserver") { |t|
t.verbose = true
}
+Rake::TestTask.new("test_db2") { |t|
+ t.libs << "test" << "test/connections/native_db2"
+ t.pattern = 'test/*_test.rb'
+ t.verbose = true
+}
+
# Generate the RDoc documentation
Rake::RDocTask.new { |rdoc|
diff --git a/activerecord/install.rb b/activerecord/install.rb
index 50c68f5d2b..b61ac815f5 100644
--- a/activerecord/install.rb
+++ b/activerecord/install.rb
@@ -38,6 +38,7 @@ files = %w-
active_record/connection_adapters/mysql_adapter.rb
active_record/connection_adapters/postgresql_adapter.rb
active_record/connection_adapters/sqlite_adapter.rb
+ active_record/connection_adapters/db2_adapter.rb
active_record/deprecated_associations.rb
active_record/fixtures.rb
active_record/observer.rb
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 963a14dd3e..3a6fe1eb6e 100755
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -58,3 +58,4 @@ require 'active_record/connection_adapters/mysql_adapter'
require 'active_record/connection_adapters/postgresql_adapter'
require 'active_record/connection_adapters/sqlite_adapter'
require 'active_record/connection_adapters/sqlserver_adapter'
+require 'active_record/connection_adapters/db2_adapter'
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 019de942b9..742491ae48 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -577,4 +577,4 @@ module ActiveRecord
end
end
end
-end
+end \ No newline at end of file
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 849fb1578b..284f06c694 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -311,7 +311,7 @@ module ActiveRecord #:nodoc:
sql << "ORDER BY #{orderings} " unless orderings.nil?
connection.add_limit!(sql, 1)
-
+
record = connection.select_one(sql, "#{name} Load First")
instantiate(record) unless record.nil?
end
@@ -919,7 +919,7 @@ module ActiveRecord #:nodoc:
# table with a master_id foreign key can instantiate master through Client#master.
def method_missing(method_id, *arguments)
method_name = method_id.id2name
-
+
if method_name =~ read_method? && @attributes.include?($1)
return read_attribute($1)
elsif method_name =~ read_untyped_method? && @attributes.include?($1)
@@ -959,7 +959,7 @@ module ActiveRecord #:nodoc:
# Returns true if the attribute is of a text column and marked for serialization.
def unserializable_attribute?(attr_name, column)
- @attributes[attr_name] && column.send(:type) == :text && @attributes[attr_name].is_a?(String) && self.class.serialized_attributes[attr_name]
+ @attributes[attr_name] && [:text, :string].include?(column.send(:type)) && @attributes[attr_name].is_a?(String) && self.class.serialized_attributes[attr_name]
end
# Returns the unserialized object of the attribute.
diff --git a/activerecord/lib/active_record/connection_adapters/db2_adapter.rb b/activerecord/lib/active_record/connection_adapters/db2_adapter.rb
new file mode 100644
index 0000000000..b4f4f24ca4
--- /dev/null
+++ b/activerecord/lib/active_record/connection_adapters/db2_adapter.rb
@@ -0,0 +1,127 @@
+# db2_adapter.rb
+# author: Maik Schmidt <contact@maik-schmidt.de>
+
+require 'active_record/connection_adapters/abstract_adapter'
+
+begin
+ require 'db2/db2cli' unless self.class.const_defined?(:DB2CLI)
+ require 'active_record/vendor/db2'
+
+ module ActiveRecord
+ class Base
+ # Establishes a connection to the database that's used by
+ # all Active Record objects
+ def self.db2_connection(config) # :nodoc:
+ symbolize_strings_in_hash(config)
+ usr = config[:username]
+ pwd = config[:password]
+
+ if config.has_key?(:database)
+ database = config[:database]
+ else
+ raise ArgumentError, "No database specified. Missing argument: database."
+ end
+
+ connection = DB2::Connection.new(DB2::Environment.new)
+ connection.connect(database, usr, pwd)
+ ConnectionAdapters::DB2Adapter.new(connection)
+ end
+ end
+
+ module ConnectionAdapters
+ class DB2Adapter < AbstractAdapter # :nodoc:
+ def select_all(sql, name = nil)
+ select(sql, name)
+ end
+
+ def select_one(sql, name = nil)
+ select(sql, name).first
+ end
+
+ def insert(sql, name = nil, pk = nil, id_value = nil)
+ execute(sql, name = nil)
+ id_value || last_insert_id
+ end
+
+ def execute(sql, name = nil)
+ rows_affected = 0
+ log(sql, name, @connection) do |connection|
+ stmt = DB2::Statement.new(connection)
+ stmt.exec_direct(sql)
+ rows_affected = stmt.row_count
+ stmt.free
+ end
+ rows_affected
+ end
+
+ alias_method :update, :execute
+ alias_method :delete, :execute
+
+ def begin_db_transaction
+ @connection.set_auto_commit_off
+ end
+
+ def commit_db_transaction
+ @connection.commit
+ @connection.set_auto_commit_on
+ end
+
+ def rollback_db_transaction
+ @connection.rollback
+ @connection.set_auto_commit_on
+ end
+
+ def quote_column_name(name) name; end
+
+ def quote_string(s)
+ s.gsub(/'/, "''") # ' (for ruby-mode)
+ end
+
+ def add_limit!(sql, limit)
+ sql << " FETCH FIRST #{limit} ROWS ONLY"
+ end
+
+ def columns(table_name, name = nil)
+ stmt = DB2::Statement.new(@connection)
+ result = []
+ stmt.columns(table_name.upcase).each do |c|
+ c_name = c[3].downcase
+ c_default = c[12] == 'NULL' ? nil : c[12]
+ c_type = c[5].downcase
+ c_type += "(#{c[6]})" if !c[6].nil? && c[6] != ''
+ result << Column.new(c_name, c_default, c_type)
+ end
+ stmt.free
+ result
+ end
+
+ private
+
+ def last_insert_id
+ row = select_one(<<-GETID.strip)
+ with temp(id) as (values (identity_val_local())) select * from temp
+ GETID
+ row['id'].to_i
+ end
+
+ def select(sql, name = nil)
+ stmt = nil
+ log(sql, name, @connection) do |connection|
+ stmt = DB2::Statement.new(connection)
+ stmt.exec_direct(sql)
+ end
+
+ rows = []
+ while row = stmt.fetch_as_hash
+ rows << row
+ end
+ stmt.free
+ rows
+ end
+ end
+ end
+ end
+rescue LoadError
+ retry if require('rubygems') rescue LoadError
+ # DB2 driver is unavailable.
+end
diff --git a/activerecord/lib/active_record/fixtures.rb b/activerecord/lib/active_record/fixtures.rb
index 21d0615dfa..1db5d29bd7 100755
--- a/activerecord/lib/active_record/fixtures.rb
+++ b/activerecord/lib/active_record/fixtures.rb
@@ -364,4 +364,4 @@ module Test#:nodoc:
end
end
end
-end \ No newline at end of file
+end
diff --git a/activerecord/lib/active_record/vendor/db2.rb b/activerecord/lib/active_record/vendor/db2.rb
new file mode 100644
index 0000000000..f0ec847d72
--- /dev/null
+++ b/activerecord/lib/active_record/vendor/db2.rb
@@ -0,0 +1,357 @@
+require 'db2/db2cli.rb'
+
+module DB2
+ module DB2Util
+ include DB2CLI
+
+ def free() SQLFreeHandle(@handle_type, @handle); end
+ def handle() @handle; end
+
+ def check_rc(rc)
+ if rc != SQL_SUCCESS and rc != SQL_SUCCESS_WITH_INFO and rc != SQL_NO_DATA_FOUND
+ rec = 1
+ msg = ''
+ loop do
+ a = SQLGetDiagRec(@handle_type, @handle, rec, 500)
+ break if a[0] != SQL_SUCCESS
+ msg << a[3] if !a[3].nil? and a[3] != '' # Create message.
+ rec += 1
+ end
+ raise "DB2 error: #{msg}"
+ end
+ end
+ end
+
+ class Environment
+ include DB2Util
+
+ def initialize
+ @handle_type = SQL_HANDLE_ENV
+ rc, @handle = SQLAllocHandle(@handle_type, SQL_NULL_HANDLE)
+ check_rc(rc)
+ end
+
+ def data_sources(buffer_length = 1024)
+ retval = []
+ max_buffer_length = buffer_length
+
+ a = SQLDataSources(@handle, SQL_FETCH_FIRST, SQL_MAX_DSN_LENGTH + 1, buffer_length)
+ retval << [a[1], a[3]]
+ max_buffer_length = [max_buffer_length, a[4]].max
+
+ loop do
+ a = SQLDataSources(@handle, SQL_FETCH_NEXT, SQL_MAX_DSN_LENGTH + 1, buffer_length)
+ break if a[0] == SQL_NO_DATA_FOUND
+
+ retval << [a[1], a[3]]
+ max_buffer_length = [max_buffer_length, a[4]].max
+ end
+
+ if max_buffer_length > buffer_length
+ get_data_sources(max_buffer_length)
+ else
+ retval
+ end
+ end
+ end
+
+ class Connection
+ include DB2Util
+
+ def initialize(environment)
+ @env = environment
+ @handle_type = SQL_HANDLE_DBC
+ rc, @handle = SQLAllocHandle(@handle_type, @env.handle)
+ check_rc(rc)
+ end
+
+ def connect(server_name, user_name = '', auth = '')
+ check_rc(SQLConnect(@handle, server_name, user_name, auth))
+ end
+
+ def set_connect_attr(attr, value)
+ value += "\0" if value.class == String
+ check_rc(SQLSetConnectAttr(@handle, attr, value))
+ end
+
+ def set_auto_commit_on
+ set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_ON)
+ end
+
+ def set_auto_commit_off
+ set_connect_attr(SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF)
+ end
+
+ def disconnect
+ check_rc(SQLDisconnect(@handle))
+ end
+
+ def rollback
+ check_rc(SQLEndTran(@handle_type, @handle, SQL_ROLLBACK))
+ end
+
+ def commit
+ check_rc(SQLEndTran(@handle_type, @handle, SQL_COMMIT))
+ end
+ end
+
+ class Statement
+ include DB2Util
+
+ def initialize(connection)
+ @conn = connection
+ @handle_type = SQL_HANDLE_STMT
+ @parms = [] #yun
+ @sql = '' #yun
+ @numParms = 0 #yun
+ @prepared = false #yun
+ @parmArray = [] #yun. attributes of the parameter markers
+ rc, @handle = SQLAllocHandle(@handle_type, @conn.handle)
+ check_rc(rc)
+ end
+
+ def columns(table_name)
+ check_rc(SQLColumns(@handle, "", "%", table_name, "%"))
+ fetch_all
+ end
+
+ def tables
+ check_rc(SQLTables(@handle, "", "%", "%", "TABLE"))
+ fetch_all
+ end
+
+ def prepare(sql)
+ @sql = sql
+ check_rc(SQLPrepare(@handle, sql))
+ rc, @numParms = SQLNumParams(@handle) #number of question marks
+ check_rc(rc)
+ #--------------------------------------------------------------------------
+ # parameter attributes are stored in instance variable @parmArray so that
+ # they are available when execute method is called.
+ #--------------------------------------------------------------------------
+ if @numParms > 0 # get parameter marker attributes
+ 1.upto(@numParms) do |i| # parameter number starts from 1
+ rc, type, size, decimalDigits = SQLDescribeParam(@handle, i)
+ check_rc(rc)
+ @parmArray << Parameter.new(type, size, decimalDigits)
+ end
+ end
+ @prepared = true
+ self
+ end
+
+ def execute(*parms)
+ raise "The statement was not prepared" if @prepared == false
+
+ if parms.size == 1 and parms[0].class == Array
+ parms = parms[0]
+ end
+
+ if @numParms != parms.size
+ raise "Number of parameters supplied does not match with the SQL statement"
+ end
+
+ if @numParms > 0 #need to bind parameters
+ #--------------------------------------------------------------------
+ #calling bindParms may not be safe. Look comment below.
+ #--------------------------------------------------------------------
+ #bindParms(parms)
+
+ valueArray = []
+ 1.upto(@numParms) do |i| # parameter number starts from 1
+ type = @parmArray[i - 1].class
+ size = @parmArray[i - 1].size
+ decimalDigits = @parmArray[i - 1].decimalDigits
+
+ if parms[i - 1].class == String
+ valueArray << parms[i - 1]
+ else
+ valueArray << parms[i - 1].to_s
+ end
+
+ rc = SQLBindParameter(@handle, i, type, size, decimalDigits, valueArray[i - 1])
+ check_rc(rc)
+ end
+ end
+
+ check_rc(SQLExecute(@handle))
+
+ if @numParms != 0
+ check_rc(SQLFreeStmt(@handle, SQL_RESET_PARAMS)) # Reset parameters
+ end
+
+ self
+ end
+
+ #-------------------------------------------------------------------------------
+ # The last argument(value) to SQLBindParameter is a deferred argument, that is,
+ # it should be available when SQLExecute is called. Even though "value" is
+ # local to bindParms method, it seems that it is available when SQLExecute
+ # is called. I am not sure whether it would still work if garbage collection
+ # is done between bindParms call and SQLExecute call inside the execute method
+ # above.
+ #-------------------------------------------------------------------------------
+ def bindParms(parms) # This is the real thing. It uses SQLBindParms
+ 1.upto(@numParms) do |i| # parameter number starts from 1
+ rc, dataType, parmSize, decimalDigits = SQLDescribeParam(@handle, i)
+ check_rc(rc)
+ if parms[i - 1].class == String
+ value = parms[i - 1]
+ else
+ value = parms[i - 1].to_s
+ end
+ rc = SQLBindParameter(@handle, i, dataType, parmSize, decimalDigits, value)
+ check_rc(rc)
+ end
+ end
+
+ #------------------------------------------------------------------------------
+ # bind method does not use DB2's SQLBindParams, but replaces "?" in the
+ # SQL statement with the value before passing the SQL statement to DB2.
+ # It is not efficient and can handle only strings since it puts everything in
+ # quotes.
+ #------------------------------------------------------------------------------
+ def bind(sql, args) #does not use SQLBindParams
+ arg_index = 0
+ result = ""
+ tokens(sql).each do |part|
+ case part
+ when '?'
+ result << "'" + (args[arg_index]) + "'" #put it into quotes
+ arg_index += 1
+ when '??'
+ result << "?"
+ else
+ result << part
+ end
+ end
+ if arg_index < args.size
+ raise "Too many SQL parameters"
+ elsif arg_index > args.size
+ raise "Not enough SQL parameters"
+ end
+ result
+ end
+
+ ## Break the sql string into parts.
+ #
+ # This is NOT a full lexer for SQL. It just breaks up the SQL
+ # string enough so that question marks, double question marks and
+ # quoted strings are separated. This is used when binding
+ # arguments to "?" in the SQL string. Note: comments are not
+ # handled.
+ #
+ def tokens(sql)
+ toks = sql.scan(/('([^'\\]|''|\\.)*'|"([^"\\]|""|\\.)*"|\?\??|[^'"?]+)/)
+ toks.collect { |t| t[0] }
+ end
+
+ def exec_direct(sql)
+ check_rc(SQLExecDirect(@handle, sql))
+ self
+ end
+
+ def set_cursor_name(name)
+ check_rc(SQLSetCursorName(@handle, name))
+ self
+ end
+
+ def get_cursor_name
+ rc, name = SQLGetCursorName(@handle)
+ check_rc(rc)
+ name
+ end
+
+ def row_count
+ rc, rowcount = SQLRowCount(@handle)
+ check_rc(rc)
+ rowcount
+ end
+
+ def num_result_cols
+ rc, cols = SQLNumResultCols(@handle)
+ check_rc(rc)
+ cols
+ end
+
+ def fetch_all
+ if block_given?
+ while row = fetch do
+ yield row
+ end
+ else
+ res = []
+ while row = fetch do
+ res << row
+ end
+ res
+ end
+ end
+
+ def fetch
+ cols = get_col_desc
+ rc = SQLFetch(@handle)
+ if rc == SQL_NO_DATA_FOUND
+ SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor
+ SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters
+ return nil
+ end
+ raise "ERROR" unless rc == SQL_SUCCESS
+
+ retval = []
+ cols.each_with_index do |c, i|
+ rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2]
+ retval << adjust_content(content)
+ end
+ retval
+ end
+
+ def fetch_as_hash
+ cols = get_col_desc
+ rc = SQLFetch(@handle)
+ if rc == SQL_NO_DATA_FOUND
+ SQLFreeStmt(@handle, SQL_CLOSE) # Close cursor
+ SQLFreeStmt(@handle, SQL_RESET_PARAMS) # Reset parameters
+ return nil
+ end
+ raise "ERROR" unless rc == SQL_SUCCESS
+
+ retval = {}
+ cols.each_with_index do |c, i|
+ rc, content = SQLGetData(@handle, i + 1, c[1], c[2] + 1) #yun added 1 to c[2]
+ retval[c[0]] = adjust_content(content)
+ end
+ retval
+ end
+
+ def get_col_desc
+ rc, nr_cols = SQLNumResultCols(@handle)
+ cols = (1..nr_cols).collect do |c|
+ rc, name, bl, type, col_sz = SQLDescribeCol(@handle, c, 1024)
+ [name.downcase, type, col_sz]
+ end
+ end
+
+ def adjust_content(c)
+ case c.class.to_s
+ when 'DB2CLI::NullClass'
+ return nil
+ when 'DB2CLI::Time'
+ "%02d:%02d:%02d" % [c.hour, c.minute, c.second]
+ when 'DB2CLI::Date'
+ "%04d-%02d-%02d" % [c.year, c.month, c.day]
+ when 'DB2CLI::Timestamp'
+ "%04d-%02d-%02d %02d:%02d:%02d" % [c.year, c.month, c.day, c.hour, c.minute, c.second]
+ else
+ return c
+ end
+ end
+ end
+
+ class Parameter
+ attr_reader :type, :size, :decimalDigits
+ def initialize(type, size, decimalDigits)
+ @type, @size, @decimalDigits = type, size, decimalDigits
+ end
+ end
+end
diff --git a/activerecord/test/associations_test.rb b/activerecord/test/associations_test.rb
index 5313485ec4..feccab09ec 100755
--- a/activerecord/test/associations_test.rb
+++ b/activerecord/test/associations_test.rb
@@ -519,7 +519,7 @@ class HasAndBelongsToManyAssociationsTest < Test::Unit::TestCase
def test_removing_associations_on_destroy
Developer.find(1).destroy
- assert Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = '1'").empty?
+ assert Developer.connection.select_all("SELECT * FROM developers_projects WHERE developer_id = 1").empty?
end
def test_additional_columns_from_join_table
diff --git a/activerecord/test/base_test.rb b/activerecord/test/base_test.rb
index 8bbf98555d..1094430dbf 100755
--- a/activerecord/test/base_test.rb
+++ b/activerecord/test/base_test.rb
@@ -119,7 +119,7 @@ class BasicsTest < Test::Unit::TestCase
def test_update
topic = Topic.new
topic.title = "Another New Topic"
- topic.written_on = "2003-12-12 23:23"
+ topic.written_on = "2003-12-12 23:23:00"
topic.save
id = topic.id
assert_equal(id, topic.id)
@@ -162,7 +162,7 @@ class BasicsTest < Test::Unit::TestCase
def test_destroy
topic = Topic.new
topic.title = "Yet Another New Topic"
- topic.written_on = "2003-12-12 23:23"
+ topic.written_on = "2003-12-12 23:23:00"
topic.save
id = topic.id
topic.destroy
@@ -585,4 +585,4 @@ class BasicsTest < Test::Unit::TestCase
assert_raises(ActiveRecord::RecordNotFound) { Topic.find(1) }
assert_nothing_raised { Reply.find(should_be_destroyed_reply.id) }
end
-end \ No newline at end of file
+end
diff --git a/activerecord/test/connections/native_db2/connection.rb b/activerecord/test/connections/native_db2/connection.rb
new file mode 100644
index 0000000000..47f323945a
--- /dev/null
+++ b/activerecord/test/connections/native_db2/connection.rb
@@ -0,0 +1,24 @@
+print "Using native DB2\n"
+require 'fixtures/course'
+require 'logger'
+
+ActiveRecord::Base.logger = Logger.new("debug.log")
+
+db1 = 'arunit'
+db2 = 'arunit2'
+
+ActiveRecord::Base.establish_connection(
+ :adapter => "db2",
+ :host => "localhost",
+ :username => "arunit",
+ :password => "arunit",
+ :database => db1
+)
+
+Course.establish_connection(
+ :adapter => "db2",
+ :host => "localhost",
+ :username => "arunit2",
+ :password => "arunit2",
+ :database => db2
+)
diff --git a/activerecord/test/fixtures/companies.yml b/activerecord/test/fixtures/companies.yml
new file mode 100644
index 0000000000..9100cfd6ab
--- /dev/null
+++ b/activerecord/test/fixtures/companies.yml
@@ -0,0 +1,21 @@
+first_client:
+ id: 2
+ type: Client
+ firm_id: 1
+ client_of: 2
+ name: Summit
+ ruby_type: Client
+
+first_firm:
+ id: 1
+ type: Firm
+ name: 37signals
+ ruby_type: Firm
+
+second_client:
+ id: 3
+ type: Client
+ firm_id: 1
+ client_of: 1
+ name: Microsoft
+ ruby_type: Client
diff --git a/activerecord/test/fixtures/companies/first_client b/activerecord/test/fixtures/companies/first_client
deleted file mode 100755
index 800c694eeb..0000000000
--- a/activerecord/test/fixtures/companies/first_client
+++ /dev/null
@@ -1,6 +0,0 @@
-id => 2
-type => Client
-firm_id => 1
-client_of => 2
-name => Summit
-ruby_type => Client
diff --git a/activerecord/test/fixtures/companies/first_firm b/activerecord/test/fixtures/companies/first_firm
deleted file mode 100755
index 22d876dad1..0000000000
--- a/activerecord/test/fixtures/companies/first_firm
+++ /dev/null
@@ -1,4 +0,0 @@
-id => 1
-type => Firm
-name => 37signals
-ruby_type => Firm
diff --git a/activerecord/test/fixtures/companies/second_client b/activerecord/test/fixtures/companies/second_client
deleted file mode 100755
index 69f8adc49c..0000000000
--- a/activerecord/test/fixtures/companies/second_client
+++ /dev/null
@@ -1,6 +0,0 @@
-id => 3
-type => Client
-firm_id => 1
-client_of => 1
-name => Microsoft
-ruby_type => Client
diff --git a/activerecord/test/fixtures/courses.yml b/activerecord/test/fixtures/courses.yml
new file mode 100644
index 0000000000..d4c0e3cfb9
--- /dev/null
+++ b/activerecord/test/fixtures/courses.yml
@@ -0,0 +1,7 @@
+java:
+ id: 2
+ name: Java Development
+
+ruby:
+ id: 1
+ name: Ruby Development
diff --git a/activerecord/test/fixtures/courses/java b/activerecord/test/fixtures/courses/java
deleted file mode 100644
index 84b10d390b..0000000000
--- a/activerecord/test/fixtures/courses/java
+++ /dev/null
@@ -1,2 +0,0 @@
-id => 2
-name => Java Development
diff --git a/activerecord/test/fixtures/courses/ruby b/activerecord/test/fixtures/courses/ruby
deleted file mode 100644
index db42f96d27..0000000000
--- a/activerecord/test/fixtures/courses/ruby
+++ /dev/null
@@ -1,2 +0,0 @@
-id => 1
-name => Ruby Development
diff --git a/activerecord/test/fixtures/customers.yml b/activerecord/test/fixtures/customers.yml
new file mode 100644
index 0000000000..1a83a54a9c
--- /dev/null
+++ b/activerecord/test/fixtures/customers.yml
@@ -0,0 +1,7 @@
+david:
+ id: 1
+ name: David
+ balance: 50
+ address_street: Funny Street
+ address_city: Scary Town
+ address_country: Loony Land
diff --git a/activerecord/test/fixtures/customers/david b/activerecord/test/fixtures/customers/david
deleted file mode 100644
index 69b9c32376..0000000000
--- a/activerecord/test/fixtures/customers/david
+++ /dev/null
@@ -1,6 +0,0 @@
-id => 1
-name => David
-balance => 50
-address_street => Funny Street
-address_city => Scary Town
-address_country => Loony Land \ No newline at end of file
diff --git a/activerecord/test/fixtures/db_definitions/db2.sql b/activerecord/test/fixtures/db_definitions/db2.sql
new file mode 100644
index 0000000000..7171bd3e16
--- /dev/null
+++ b/activerecord/test/fixtures/db_definitions/db2.sql
@@ -0,0 +1,112 @@
+CREATE TABLE accounts (
+ id int generated by default as identity (start with +10000),
+ firm_id int default NULL,
+ credit_limit int default NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE companies (
+ id int generated by default as identity (start with +10000),
+ type varchar(50) default NULL,
+ ruby_type varchar(50) default NULL,
+ firm_id int default NULL,
+ name varchar(50) default NULL,
+ client_of int default NULL,
+ rating int default 1,
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE topics (
+ id int generated by default as identity (start with +10000),
+ title varchar(255) default NULL,
+ author_name varchar(255) default NULL,
+ author_email_address varchar(255) default NULL,
+ written_on timestamp default NULL,
+ bonus_time time default NULL,
+ last_read date default NULL,
+ content varchar(3000),
+ approved smallint default 1,
+ replies_count int default 0,
+ parent_id int default NULL,
+ type varchar(50) default NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE developers (
+ id int generated by default as identity (start with +10000),
+ name varchar(100) default NULL,
+ salary int default 70000,
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE projects (
+ id int generated by default as identity (start with +10000),
+ name varchar(100) default NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE developers_projects (
+ developer_id int NOT NULL,
+ project_id int NOT NULL,
+ joined_on date default NULL
+);
+
+CREATE TABLE customers (
+ id int generated by default as identity (start with +10000),
+ name varchar(100) default NULL,
+ balance int default 0,
+ address_street varchar(100) default NULL,
+ address_city varchar(100) default NULL,
+ address_country varchar(100) default NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE movies (
+ movieid int generated by default as identity (start with +10000),
+ name varchar(100) default NULL,
+ PRIMARY KEY (movieid)
+);
+
+CREATE TABLE subscribers (
+ nick varchar(100) NOT NULL,
+ name varchar(100) default NULL,
+ PRIMARY KEY (nick)
+);
+
+CREATE TABLE booleantests (
+ id int generated by default as identity (start with +10000),
+ value int default NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE auto_id_tests (
+ auto_id int generated by default as identity (start with +10000),
+ value int default NULL,
+ PRIMARY KEY (auto_id)
+);
+
+CREATE TABLE entrants (
+ id int NOT NULL PRIMARY KEY,
+ name varchar(255) NOT NULL,
+ course_id int NOT NULL
+);
+
+CREATE TABLE colnametests (
+ id int generated by default as identity (start with +10000),
+ references int NOT NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE TABLE mixins (
+ id int generated by default as identity (start with +10000),
+ parent_id int default NULL,
+ pos int default NULL,
+ created_at timestamp default NULL,
+ updated_at timestamp default NULL,
+ lft int default NULL,
+ rgt int default NULL,
+ root_id int default NULL,
+ type varchar(40) default NULL,
+ PRIMARY KEY (id)
+);
+
diff --git a/activerecord/test/fixtures/db_definitions/db22.sql b/activerecord/test/fixtures/db_definitions/db22.sql
new file mode 100644
index 0000000000..dc4f9ed364
--- /dev/null
+++ b/activerecord/test/fixtures/db_definitions/db22.sql
@@ -0,0 +1,4 @@
+CREATE TABLE courses (
+ id int NOT NULL PRIMARY KEY,
+ name varchar(255) NOT NULL
+);
diff --git a/activerecord/test/fixtures/developers_projects.yml b/activerecord/test/fixtures/developers_projects.yml
new file mode 100644
index 0000000000..b1194a6f16
--- /dev/null
+++ b/activerecord/test/fixtures/developers_projects.yml
@@ -0,0 +1,13 @@
+david_action_controller:
+ developer_id: 1
+ project_id: 2
+ joined_on: 2004-10-10
+
+david_active_record:
+ developer_id: 1
+ project_id: 1
+ joined_on: 2004-10-10
+
+jamis_active_record:
+ developer_id: 2
+ project_id: 1
diff --git a/activerecord/test/fixtures/entrants.yml b/activerecord/test/fixtures/entrants.yml
new file mode 100644
index 0000000000..86f0108e52
--- /dev/null
+++ b/activerecord/test/fixtures/entrants.yml
@@ -0,0 +1,14 @@
+first:
+ id: 1
+ course_id: 1
+ name: Ruby Developer
+
+second:
+ id: 2
+ course_id: 1
+ name: Ruby Guru
+
+third:
+ id: 3
+ course_id: 2
+ name: Java Lover
diff --git a/activerecord/test/fixtures/entrants/first b/activerecord/test/fixtures/entrants/first
deleted file mode 100644
index e45cd6c1c2..0000000000
--- a/activerecord/test/fixtures/entrants/first
+++ /dev/null
@@ -1,3 +0,0 @@
-id => 1
-course_id => 1
-name => Ruby Developer
diff --git a/activerecord/test/fixtures/entrants/second b/activerecord/test/fixtures/entrants/second
deleted file mode 100644
index 38cd702476..0000000000
--- a/activerecord/test/fixtures/entrants/second
+++ /dev/null
@@ -1,3 +0,0 @@
-id => 2
-course_id => 1
-name => Ruby Guru
diff --git a/activerecord/test/fixtures/entrants/third b/activerecord/test/fixtures/entrants/third
deleted file mode 100644
index 594ac77af0..0000000000
--- a/activerecord/test/fixtures/entrants/third
+++ /dev/null
@@ -1,3 +0,0 @@
-id => 3
-course_id => 2
-name => Java Lover
diff --git a/activerecord/test/fixtures/movies.yml b/activerecord/test/fixtures/movies.yml
new file mode 100644
index 0000000000..2e9154fda8
--- /dev/null
+++ b/activerecord/test/fixtures/movies.yml
@@ -0,0 +1,7 @@
+first:
+ movieid: 1
+ name: Terminator
+
+second:
+ movieid: 2
+ name: Gladiator
diff --git a/activerecord/test/fixtures/movies/first b/activerecord/test/fixtures/movies/first
deleted file mode 100644
index 0feaeac7b0..0000000000
--- a/activerecord/test/fixtures/movies/first
+++ /dev/null
@@ -1,2 +0,0 @@
-movieid => 1
-name => Terminator
diff --git a/activerecord/test/fixtures/movies/second b/activerecord/test/fixtures/movies/second
deleted file mode 100644
index b3c506b7da..0000000000
--- a/activerecord/test/fixtures/movies/second
+++ /dev/null
@@ -1,2 +0,0 @@
-movieid => 2
-name => Gladiator
diff --git a/activerecord/test/fixtures/projects.yml b/activerecord/test/fixtures/projects.yml
new file mode 100644
index 0000000000..02800c7824
--- /dev/null
+++ b/activerecord/test/fixtures/projects.yml
@@ -0,0 +1,7 @@
+action_controller:
+ id: 2
+ name: Active Controller
+
+active_record:
+ id: 1
+ name: Active Record
diff --git a/activerecord/test/fixtures/projects/action_controller b/activerecord/test/fixtures/projects/action_controller
deleted file mode 100644
index b3f00ae727..0000000000
--- a/activerecord/test/fixtures/projects/action_controller
+++ /dev/null
@@ -1,2 +0,0 @@
-id => 2
-name => Active Controller \ No newline at end of file
diff --git a/activerecord/test/fixtures/projects/active_record b/activerecord/test/fixtures/projects/active_record
deleted file mode 100644
index 31131a7f30..0000000000
--- a/activerecord/test/fixtures/projects/active_record
+++ /dev/null
@@ -1,2 +0,0 @@
-id => 1
-name => Active Record \ No newline at end of file
diff --git a/activerecord/test/fixtures/topics.yml b/activerecord/test/fixtures/topics.yml
new file mode 100644
index 0000000000..5571bd914c
--- /dev/null
+++ b/activerecord/test/fixtures/topics.yml
@@ -0,0 +1,21 @@
+first:
+ id: 1
+ title: The First Topic
+ author_name: David
+ author_email_address: david@loudthinking.com
+ written_on: 2003-07-16 15:28:00
+ bonus_time: 12:13:14
+ last_read: 2004-04-15
+ content: Have a nice day
+ approved: 0
+ replies_count: 0
+
+second:
+ id: 2
+ title: The Second Topic's of the day
+ author_name: Mary
+ written_on: 2003-07-15 15:28:00
+ content: Have a great day!
+ approved: 1
+ replies_count: 2
+ parent_id: 1
diff --git a/activerecord/test/fixtures/topics/first b/activerecord/test/fixtures/topics/first
deleted file mode 100755
index 2e1a88563b..0000000000
--- a/activerecord/test/fixtures/topics/first
+++ /dev/null
@@ -1,10 +0,0 @@
-id => 1
-title => The First Topic
-author_name => David
-author_email_address => david@loudthinking.com
-written_on => 2003-07-16 15:28
-bonus_time => 12:13:14
-last_read => 2004-04-15
-content => Have a nice day
-approved => 0
-replies_count => 0 \ No newline at end of file
diff --git a/activerecord/test/fixtures/topics/second b/activerecord/test/fixtures/topics/second
deleted file mode 100755
index f669b4fef4..0000000000
--- a/activerecord/test/fixtures/topics/second
+++ /dev/null
@@ -1,8 +0,0 @@
-id => 2
-title => The Second Topic's of the day
-author_name => Mary
-written_on => 2003-07-15 15:28
-content => Have a great day!
-approved => 1
-replies_count => 2
-parent_id => 1 \ No newline at end of file