ActiveRecord-JDBC 0.2.2 → 0.2.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/History.txt ADDED
@@ -0,0 +1,13 @@
1
+ == 0.2.3
2
+
3
+ * Release coincides (and compatible) with JRuby 0.9.8 release
4
+ * 8 bugs fixed: see http://rubyurl.com/0Da
5
+ * Improvements and compatibility fixes for Rails 1.2.x
6
+
7
+ == 0.2.1, 0.2.2
8
+
9
+ * Early releases, added better support for multiple databases
10
+
11
+ == 0.0.1
12
+
13
+ * Initial, very alpha release
data/Manifest.txt ADDED
@@ -0,0 +1,41 @@
1
+ History.txt
2
+ Manifest.txt
3
+ README.txt
4
+ Rakefile
5
+ LICENSE
6
+ lib/jdbc_adapter.rb
7
+ lib/active_record/connection_adapters/jdbc_adapter.rb
8
+ lib/active_record/connection_adapters/jdbc_adapter_spec.rb
9
+ lib/active_record/connection_adapters/jndi_adapter.rb
10
+ lib/jdbc_adapter/jdbc_db2.rb
11
+ lib/jdbc_adapter/jdbc_derby.rb
12
+ lib/jdbc_adapter/jdbc_firebird.rb
13
+ lib/jdbc_adapter/jdbc_hsqldb.rb
14
+ lib/jdbc_adapter/jdbc_mimer.rb
15
+ lib/jdbc_adapter/jdbc_mssql.rb
16
+ lib/jdbc_adapter/jdbc_mysql.rb
17
+ lib/jdbc_adapter/jdbc_oracle.rb
18
+ lib/jdbc_adapter/jdbc_postgre.rb
19
+ test/derby_simple_test.rb
20
+ test/h2_simple_test.rb
21
+ test/hsqldb_simple_test.rb
22
+ test/manualTestDatabase.rb
23
+ test/minirunit.rb
24
+ test/mysql_simple_test.rb
25
+ test/simple.rb
26
+ test/activerecord/connection_adapters/type_conversion_test.rb
27
+ test/activerecord/connections/native_jdbc_mysql/connection.rb
28
+ test/db/derby.rb
29
+ test/db/h2.rb
30
+ test/db/hsqldb.rb
31
+ test/db/logger.rb
32
+ test/db/mysql.rb
33
+ test/minirunit/testConnect.rb
34
+ test/minirunit/testH2.rb
35
+ test/minirunit/testHsqldb.rb
36
+ test/minirunit/testLoadActiveRecord.rb
37
+ test/minirunit/testMysql.rb
38
+ test/minirunit/testRawSelect.rb
39
+ test/models/auto_id.rb
40
+ test/models/data_types.rb
41
+ test/models/entry.rb
data/README.txt ADDED
@@ -0,0 +1,94 @@
1
+ ActiveRecord-JDBC is a database adapter for Rails' ActiveRecord component that can be used with JRuby[http://www.jruby.org/]. It allows use of virtually any JDBC-compliant database with your JRuby on Rails application.
2
+
3
+ ActiveRecord JDBC is a sub-project of jruby-extras at RubyForge.
4
+
5
+ == Databases
6
+
7
+ What's there, and what is not there:
8
+
9
+ * MySQL - Complete support
10
+ * PostgreSQL - Complete support
11
+ * Oracle - Complete support
12
+ * Microsoft SQL Server - Complete support except for change_column_default
13
+ * DB2 - Complete, except for the migrations:
14
+ * change_column
15
+ * change_column_default
16
+ * remove_column
17
+ * rename_column
18
+ * add_index
19
+ * remove_index
20
+ * rename_table
21
+ * FireBird - Complete, except for change_column_default and rename_column
22
+ * Derby - Complete, except for:
23
+ * change_column
24
+ * change_column_default
25
+ * remove_column
26
+ * rename_column
27
+ * HSQLDB - Complete
28
+
29
+ Other databases will require testing and likely a custom configuration module. Please join the
30
+ jruby-extras mailing-list[http://rubyforge.org/mail/?group_id=2014] to help us discover support for more databases.
31
+
32
+ == Using ActiveRecord JDBC
33
+
34
+ === Standalone, with ActiveRecord
35
+
36
+ 1. Install the gem with JRuby:
37
+ jruby --command gem install ActiveRecord-JDBC
38
+ 2. Ensure the following code gets executed in your script:
39
+ require 'rubygems'
40
+ gem 'ActiveRecord-JDBC'
41
+ require 'jdbc_adapter'
42
+ require 'active_record'
43
+
44
+ 3. After this you can establish a JDBC connection like this:
45
+ ActiveRecord::Base.establish_connection(
46
+ :adapter => 'jdbc',
47
+ :driver => 'org.apache.derby.jdbc.EmbeddedDriver',
48
+ :url => 'jdbc:derby:test_ar;create=true'
49
+ )
50
+
51
+ Provided you have the derby libraries in your classpath, this is enough
52
+ to establish an in-memory JDBC connection. The required parameters to
53
+ establish_connection for ActiveRecord JDBC are:
54
+
55
+ * adapter
56
+ * driver
57
+ * url
58
+
59
+ If provided, password and username will be used. After the connection is established
60
+ Active Record can be used as usual.
61
+
62
+ === Inside Rails
63
+
64
+ To use ActiveRecord-JDBC with JRuby on Rails:
65
+
66
+ 1. Install the gem with JRuby:
67
+ jruby --command gem install ActiveRecord-JDBC
68
+ 2. Add one-time setup to your config/environment.rb file in your Rails application. Add the following lines just before the <code>Rails::Initializer</code>.
69
+ require 'rubygems'
70
+ gem 'ActiveRecord-JDBC'
71
+ require 'jdbc_adapter'
72
+ 3. Configure your database.yml to use the <code>jdbc</code> adapter. For now, you'll need to know the database driver class and URL. Example:
73
+ development:
74
+ adapter: jdbc
75
+ username: blog
76
+ password:
77
+ driver: com.mysql.jdbc.Driver
78
+ url: jdbc:mysql://localhost:3306/weblog_development
79
+
80
+ == Running AR-JDBC's Tests
81
+
82
+ By default hsql, mysql, and derby are run. In order to run all tests you
83
+ must download each of the databases about put their JDBC drivers in your
84
+ classpath. Here is an example of I use:
85
+
86
+ CLASSPATH=~/opt/derby/lib/derby.jar:~/opt/mysql/mysql-connector-java-3.1.14-bin.jar:~/opt/hsqldb/lib/hsqldb.jar jruby ../jruby/bin/jruby --command rake
87
+
88
+ == Authors
89
+
90
+ This project was written by Nick Sieger <nick@nicksieger.com> and Ola Bini <ola@ologix.com> with lots of help from the JRuby community.
91
+
92
+ == License
93
+
94
+ ActiveRecord-JDBC is released under a BSD license. See the LICENSE file included with the distribution for details.
data/Rakefile ADDED
@@ -0,0 +1,55 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ task :default => :test
5
+
6
+ desc "Run AR-JDBC tests"
7
+ if RUBY_PLATFORM =~ /java/
8
+ task :test => [:test_mysql, :test_hsqldb, :test_derby]
9
+ else
10
+ task :test => [:test_mysql]
11
+ end
12
+
13
+ Rake::TestTask.new(:test_mysql) do |t|
14
+ t.test_files = FileList['test/mysql_simple_test.rb']
15
+ t.libs << 'test'
16
+ end
17
+
18
+ Rake::TestTask.new(:test_hsqldb) do |t|
19
+ t.test_files = FileList['test/hsqldb_simple_test.rb']
20
+ t.libs << 'test'
21
+ end
22
+
23
+ Rake::TestTask.new(:test_derby) do |t|
24
+ t.test_files = FileList['test/derby_simple_test.rb',
25
+ 'test/activerecord/connection_adapters/type_conversion_test.rb']
26
+ t.libs << 'test'
27
+ end
28
+
29
+ begin
30
+ require 'hoe'
31
+
32
+ MANIFEST = FileList["History.txt", "Manifest.txt", "README.txt",
33
+ "Rakefile", "LICENSE", "lib/**/*.rb", "test/**/*.rb"]
34
+
35
+ Hoe.new("ActiveRecord-JDBC", "0.2.3") do |p|
36
+ p.rubyforge_name = "jruby-extras"
37
+ p.url = "http://jruby-extras.rubyforge.org/ActiveRecord-JDBC"
38
+ p.author = "Nick Sieger, Ola Bini and JRuby contributors"
39
+ p.email = "nick@nicksieger.com, ola.bini@ki.se"
40
+ p.summary = "JDBC adapter for ActiveRecord, for use within JRuby on Rails."
41
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
42
+ p.description = p.paragraphs_of('README.txt', 0...1).join("\n\n")
43
+ p.extra_deps.reject!{|d| d.first == "hoe"}
44
+ end.spec.files = MANIFEST
45
+
46
+ # Automated manifest
47
+ task :manifest do
48
+ File.open("Manifest.txt", "w") {|f| MANIFEST.each {|n| f << "#{n}\n"} }
49
+ end
50
+
51
+ task :package => :manifest
52
+ rescue => e
53
+ # Install hoe in order to make a release
54
+ # puts e.inspect
55
+ end
@@ -1,4 +1,5 @@
1
1
  require 'active_record/connection_adapters/abstract_adapter'
2
+ require 'java'
2
3
  require 'active_record/connection_adapters/jdbc_adapter_spec'
3
4
 
4
5
  module ActiveRecord
@@ -19,16 +20,36 @@ module ActiveRecord
19
20
 
20
21
  module ConnectionAdapters
21
22
  module Java
22
- include_class 'java.lang.Class'
23
- include_class 'java.net.URL'
24
- include_class 'java.net.URLClassLoader'
23
+ Class = java.lang.Class
24
+ URL = java.net.URL
25
+ URLClassLoader = java.net.URLClassLoader
25
26
  end
26
27
 
27
28
  module Jdbc
28
- require 'java'
29
- include_class 'java.sql.DriverManager'
30
- include_class 'java.sql.Statement'
31
- include_class 'java.sql.Types'
29
+ DriverManager = java.sql.DriverManager
30
+ Statement = java.sql.Statement
31
+ Types = java.sql.Types
32
+
33
+ # some symbolic constants for the benefit of the JDBC-based
34
+ # JdbcConnection#indexes method
35
+ module IndexMetaData
36
+ INDEX_NAME = 6
37
+ NON_UNIQUE = 4
38
+ TABLE_NAME = 3
39
+ COLUMN_NAME = 9
40
+ end
41
+
42
+ module TableMetaData
43
+ TABLE_CAT = 1
44
+ TABLE_SCHEM = 2
45
+ TABLE_NAME = 3
46
+ TABLE_TYPE = 4
47
+ end
48
+
49
+ module PrimaryKeyMetaData
50
+ COLUMN_NAME = 4
51
+ end
52
+
32
53
  end
33
54
 
34
55
  # I want to use JDBC's DatabaseMetaData#getTypeInfo to choose the best native types to
@@ -57,6 +78,8 @@ module ActiveRecord
57
78
  lambda {|r| r['type_name'] =~ /^integer$/i},
58
79
  lambda {|r| r['type_name'] =~ /^int4$/i},
59
80
  lambda {|r| r['type_name'] =~ /^int$/i}],
81
+ :decimal => [ lambda {|r| Jdbc::Types::DECIMAL == r['data_type']},
82
+ lambda {|r| r['type_name'] =~ /^decimal$/i}],
60
83
  :float => [ lambda {|r| [Jdbc::Types::FLOAT,Jdbc::Types::DOUBLE].include?(r['data_type'])},
61
84
  lambda {|r| r['type_name'] =~ /^float/i},
62
85
  lambda {|r| r['type_name'] =~ /^double$/i},
@@ -71,7 +94,7 @@ module ActiveRecord
71
94
  lambda {|r| r['type_name'] =~ /^time$/i},
72
95
  lambda {|r| r['type_name'] =~ /^datetime$/i}],
73
96
  :date => [ lambda {|r| Jdbc::Types::DATE == r['data_type']},
74
- lambda {|r| r['type_name'] =~ /^datetime$/i}],
97
+ lambda {|r| r['type_name'] =~ /^date$/i}],
75
98
  :binary => [ lambda {|r| [Jdbc::Types::LONGVARBINARY,Jdbc::Types::BINARY,Jdbc::Types::BLOB].include?(r['data_type'])},
76
99
  lambda {|r| r['type_name'] =~ /^blob/i},
77
100
  lambda {|r| r['type_name'] =~ /sub_type 0$/i}, # For FireBird
@@ -80,7 +103,7 @@ module ActiveRecord
80
103
  :boolean => [ lambda {|r| [Jdbc::Types::TINYINT].include?(r['data_type'])},
81
104
  lambda {|r| r['type_name'] =~ /^bool/i},
82
105
  lambda {|r| r['type_name'] =~ /^tinyint$/i},
83
- lambda {|r| r['type_name'] =~ /^decimal$/i}]
106
+ lambda {|r| r['type_name'] =~ /^decimal$/i}],
84
107
  }
85
108
 
86
109
  def initialize(types)
@@ -91,8 +114,8 @@ module ActiveRecord
91
114
  type_map = {}
92
115
  AR_TO_JDBC_TYPES.each_key do |k|
93
116
  typerow = choose_type(k)
94
- type_map[k] = { :name => typerow['type_name'] }
95
- type_map[k][:limit] = typerow['precision'] if [:integer, :string].include?(k)
117
+ type_map[k] = { :name => typerow['type_name'] }
118
+ type_map[k][:limit] = typerow['precision'] if [:integer, :string, :decimal].include?(k)
96
119
  type_map[k][:limit] = 1 if k == :boolean
97
120
  end
98
121
  type_map
@@ -123,28 +146,35 @@ module ActiveRecord
123
146
  end
124
147
 
125
148
  class JdbcColumn < Column
149
+ COLUMN_TYPES = {
150
+ /oracle/i => lambda {|cfg,col| col.extend(JdbcSpec::Oracle::Column)},
151
+ /postgre/i => lambda {|cfg,col| col.extend(JdbcSpec::PostgreSQL::Column)},
152
+ /sqlserver|tds/i => lambda {|cfg,col| col.extend(JdbcSpec::MsSQL::Column)},
153
+ /hsqldb|\.h2\./i => lambda {|cfg,col| col.extend(JdbcSpec::HSQLDB::Column)},
154
+ /derby/i => lambda {|cfg,col| col.extend(JdbcSpec::Derby::Column)},
155
+ /db2/i => lambda {|cfg,col|
156
+ if cfg[:url] =~ /^jdbc:derby:net:/
157
+ col.extend(JdbcSpec::Derby::Column)
158
+ else
159
+ col.extend(JdbcSpec::DB2::Column)
160
+ end }
161
+ }
162
+
126
163
  def initialize(config, name, default, *args)
127
- case config[:driver].to_s
128
- when /oracle/i: self.extend(JdbcSpec::Oracle::Column)
129
- when /postgre/i: self.extend(JdbcSpec::PostgreSQL::Column)
130
- when /sqlserver|tds/i: self.extend(JdbcSpec::MsSQL::Column)
131
- when /hsqldb/i: self.extend(JdbcSpec::HSQLDB::Column)
132
- when /derby/i: self.extend(JdbcSpec::Derby::Column)
133
- when /db2/i:
134
- if config[:url] =~ /^jdbc:derby:net:/
135
- self.extend(JdbcSpec::Derby::Column)
136
- else
137
- self.extend(JdbcSpec::DB2::Column)
138
- end
164
+ ds = config[:driver].to_s
165
+ for reg, func in COLUMN_TYPES
166
+ if reg === ds
167
+ func.call(config,self)
168
+ end
139
169
  end
140
170
  super(name,default_value(default),*args)
141
- end
171
+ end
142
172
 
143
173
  def default_value(val)
144
174
  val
145
175
  end
146
176
  end
147
-
177
+
148
178
  class JdbcConnection
149
179
  def initialize(config)
150
180
  @config = config.symbolize_keys
@@ -169,7 +199,7 @@ module ActiveRecord
169
199
  def ps(sql)
170
200
  @connection.prepareStatement(sql)
171
201
  end
172
-
202
+
173
203
  def set_native_database_types
174
204
  types = unmarshal_result(@connection.getMetaData.getTypeInfo)
175
205
  @native_types = JdbcTypeConverter.new(types).choose_best_types
@@ -177,10 +207,10 @@ module ActiveRecord
177
207
 
178
208
  def native_database_types(adapt)
179
209
  types = {}
180
- @native_types.each_pair {|k,v| types[k] = v.inject({}) {|memo,kv| memo.merge({kv.first => kv.last.dup})}}
210
+ @native_types.each_pair {|k,v| types[k] = v.inject({}) {|memo,kv| memo.merge({kv.first => (kv.last.dup rescue kv.last)})}}
181
211
  adapt.modify_types(types)
182
212
  end
183
-
213
+
184
214
  def columns(table_name, name = nil)
185
215
  metadata = @connection.getMetaData
186
216
  table_name.upcase! if metadata.storesUpperCaseIdentifiers
@@ -188,23 +218,112 @@ module ActiveRecord
188
218
  results = metadata.getColumns(nil, nil, table_name, nil)
189
219
  columns = []
190
220
  unmarshal_result(results).each do |col|
191
- columns << ActiveRecord::ConnectionAdapters::JdbcColumn.new(@config,col['column_name'].downcase, col['column_def'],
192
- "#{col['type_name']}(#{col['column_size']})", col['is_nullable'] != 'NO')
221
+ column_name = col['column_name']
222
+ column_name = column_name.downcase if metadata.storesUpperCaseIdentifiers
223
+ precision = col["column_size"]
224
+ scale = col["decimal_digits"]
225
+ coltype = col["type_name"]
226
+ if precision && precision > 0
227
+ coltype << "(#{precision}"
228
+ coltype << ",#{scale}" if scale && scale > 0
229
+ coltype << ")"
230
+ end
231
+ columns << ActiveRecord::ConnectionAdapters::JdbcColumn.new(@config, column_name, col['column_def'],
232
+ coltype, col['is_nullable'] != 'NO')
193
233
  end
194
234
  columns
235
+ rescue
236
+ if @connection.is_closed
237
+ reconnect!
238
+ retry
239
+ else
240
+ raise
241
+ end
195
242
  end
196
243
 
197
- def tables
244
+ def tables(&table_filter)
198
245
  metadata = @connection.getMetaData
199
246
  results = metadata.getTables(nil, nil, nil, nil)
200
- unmarshal_result(results).collect {|t| t['table_name']}
247
+ unmarshal_result(results, &table_filter).collect {|t| t['table_name'].downcase }
248
+ rescue
249
+ if @connection.is_closed
250
+ reconnect!
251
+ retry
252
+ else
253
+ raise
254
+ end
255
+ end
256
+
257
+ # Get a list of all primary keys associated with the given table
258
+ def primary_keys(table_name)
259
+ meta_data = @connection.getMetaData
260
+ result_set = meta_data.get_primary_keys(nil, nil, table_name.to_s.upcase)
261
+ key_names = []
262
+
263
+ while result_set.next
264
+ key_names << result_set.get_string(Jdbc::PrimaryKeyMetaData::COLUMN_NAME).downcase
265
+ end
266
+
267
+ key_names
268
+ end
269
+
270
+ # Default JDBC introspection for index metadata on the JdbcConnection.
271
+ # This is currently used for migrations by JdbcSpec::HSQDLB and JdbcSpec::Derby
272
+ # indexes with a little filtering tacked on.
273
+ #
274
+ # JDBC index metadata is denormalized (multiple rows may be returned for
275
+ # one index, one row per column in the index), so a simple block-based
276
+ # filter like that used for tables doesn't really work here. Callers
277
+ # should filter the return from this method instead.
278
+ def indexes(table_name, name = nil)
279
+ metadata = @connection.getMetaData
280
+ resultset = metadata.getIndexInfo(nil, nil, table_name.to_s.upcase, false, false)
281
+ primary_keys = primary_keys(table_name)
282
+ indexes = []
283
+ current_index = nil
284
+ while resultset.next
285
+ index_name = resultset.get_string(Jdbc::IndexMetaData::INDEX_NAME).downcase
286
+ column_name = resultset.get_string(Jdbc::IndexMetaData::COLUMN_NAME).downcase
287
+
288
+ next if primary_keys.include? column_name
289
+
290
+ # We are working on a new index
291
+ if current_index != index_name
292
+ current_index = index_name
293
+ table_name = resultset.get_string(Jdbc::IndexMetaData::TABLE_NAME).downcase
294
+ non_unique = resultset.get_boolean(Jdbc::IndexMetaData::NON_UNIQUE)
295
+
296
+ # empty list for column names, we'll add to that in just a bit
297
+ indexes << IndexDefinition.new(table_name, index_name, !non_unique, [])
298
+ end
299
+
300
+ # One or more columns can be associated with an index
301
+ indexes.last.columns << column_name
302
+ end
303
+ resultset.close
304
+ indexes
305
+ rescue
306
+ if @connection.is_closed
307
+ reconnect!
308
+ retry
309
+ else
310
+ raise
311
+ end
201
312
  end
202
313
 
314
+
203
315
  def execute_insert(sql, pk)
204
316
  stmt = @connection.createStatement
205
317
  stmt.executeUpdate(sql,Jdbc::Statement::RETURN_GENERATED_KEYS)
206
318
  row = unmarshal_id_result(stmt.getGeneratedKeys)
207
319
  row.first && row.first.values.first
320
+ rescue
321
+ if @connection.is_closed
322
+ reconnect!
323
+ retry
324
+ else
325
+ raise
326
+ end
208
327
  ensure
209
328
  stmt.close
210
329
  end
@@ -212,6 +331,13 @@ module ActiveRecord
212
331
  def execute_update(sql)
213
332
  stmt = @connection.createStatement
214
333
  stmt.executeUpdate(sql)
334
+ rescue
335
+ if @connection.is_closed
336
+ reconnect!
337
+ retry
338
+ else
339
+ raise
340
+ end
215
341
  ensure
216
342
  stmt.close
217
343
  end
@@ -219,6 +345,13 @@ module ActiveRecord
219
345
  def execute_query(sql)
220
346
  stmt = @connection.createStatement
221
347
  unmarshal_result(stmt.executeQuery(sql))
348
+ rescue
349
+ if @connection.is_closed
350
+ reconnect!
351
+ retry
352
+ else
353
+ raise
354
+ end
222
355
  ensure
223
356
  stmt.close
224
357
  end
@@ -240,7 +373,7 @@ module ActiveRecord
240
373
  end
241
374
 
242
375
  private
243
- def unmarshal_result(resultset)
376
+ def unmarshal_result(resultset, &row_filter)
244
377
  metadata = resultset.getMetaData
245
378
  column_count = metadata.getColumnCount
246
379
  column_names = ['']
@@ -252,15 +385,22 @@ module ActiveRecord
252
385
  column_types << metadata.getColumnType(i)
253
386
  column_scale << metadata.getScale(i)
254
387
  end
255
-
388
+
256
389
  results = []
257
390
 
391
+ # take all rows if block not supplied
392
+ row_filter = lambda{|result_row| true} unless block_given?
393
+
258
394
  while resultset.next
259
- row = {}
260
- 1.upto(column_count) do |i|
261
- row[column_names[i].downcase] = convert_jdbc_type_to_ruby(i, column_types[i], column_scale[i], resultset)
395
+ # let the supplied block look at this row from the resultset to
396
+ # see if we want to include it in our results
397
+ if row_filter.call(resultset)
398
+ row = {}
399
+ 1.upto(column_count) do |i|
400
+ row[column_names[i].downcase] = convert_jdbc_type_to_ruby(i, column_types[i], column_scale[i], resultset)
401
+ end
402
+ results << row
262
403
  end
263
- results << row
264
404
  end
265
405
 
266
406
  results
@@ -289,71 +429,98 @@ module ActiveRecord
289
429
 
290
430
  results
291
431
  end
292
-
293
- def to_ruby_time(java_date)
294
- if java_date
295
- tm = java_date.getTime
432
+
433
+ def to_ruby_time(java_time)
434
+ if java_time
435
+ tm = java_time.getTime
296
436
  Time.at(tm / 1000, (tm % 1000) * 1000)
297
437
  end
298
438
  end
299
439
 
440
+ def to_ruby_date(java_date)
441
+ if java_date
442
+ cal = java.util.Calendar.getInstance
443
+ cal.setTime(java_date)
444
+ Date.new(cal.get(java.util.Calendar::YEAR), cal.get(java.util.Calendar::MONTH)+1, cal.get(java.util.Calendar::DATE))
445
+ end
446
+ end
447
+
300
448
  def convert_jdbc_type_to_ruby(row, type, scale, resultset)
301
- if scale != 0
302
- decimal = resultset.getString(row)
303
- decimal.to_f
304
- else
305
- case type
306
- when Jdbc::Types::CHAR, Jdbc::Types::VARCHAR, Jdbc::Types::LONGVARCHAR, Jdbc::Types::CLOB
307
- resultset.getString(row)
308
- when Jdbc::Types::SMALLINT, Jdbc::Types::INTEGER, Jdbc::Types::NUMERIC, Jdbc::Types::BIGINT
309
- resultset.getInt(row)
310
- when Jdbc::Types::BIT, Jdbc::Types::BOOLEAN, Jdbc::Types::TINYINT, Jdbc::Types::DECIMAL
311
- resultset.getBoolean(row)
312
- when Jdbc::Types::FLOAT, Jdbc::Types::DOUBLE
313
- resultset.getDouble(row)
314
- when Jdbc::Types::TIMESTAMP
315
- to_ruby_time(resultset.getTimestamp(row))
316
- when Jdbc::Types::TIME
317
- to_ruby_time(resultset.getTime(row))
318
- when Jdbc::Types::DATE
319
- to_ruby_time(resultset.getDate(row))
320
- when Jdbc::Types::LONGVARBINARY, Jdbc::Types::BLOB, Jdbc::Types::BINARY, Jdbc::Types::VARBINARY
321
- resultset.getString(row)
449
+ value = case type
450
+ when Jdbc::Types::CHAR, Jdbc::Types::VARCHAR, Jdbc::Types::LONGVARCHAR, Jdbc::Types::CLOB
451
+ resultset.getString(row)
452
+ when Jdbc::Types::NUMERIC, Jdbc::Types::BIGINT
453
+ if scale != 0
454
+ BigDecimal.new(resultset.getBigDecimal(row).toString)
322
455
  else
323
- types = Jdbc::Types.constants
324
- name = types.find {|t| Jdbc::Types.const_get(t.to_sym) == type}
325
- raise "jdbc_adapter: type #{name} not supported yet"
456
+ resultset.getLong(row)
326
457
  end
458
+ when Jdbc::Types::DECIMAL
459
+ BigDecimal.new(resultset.getBigDecimal(row).toString)
460
+ when Jdbc::Types::SMALLINT, Jdbc::Types::INTEGER
461
+ resultset.getInt(row)
462
+ when Jdbc::Types::BIT, Jdbc::Types::BOOLEAN, Jdbc::Types::TINYINT
463
+ resultset.getBoolean(row)
464
+ when Jdbc::Types::FLOAT, Jdbc::Types::DOUBLE
465
+ resultset.getDouble(row)
466
+ when Jdbc::Types::TIMESTAMP
467
+ # FIXME: This should not be a catchall and it should move this to mysql since it
468
+ # is catching non-existent date 0000-00:00:00
469
+ begin
470
+ to_ruby_time(resultset.getTimestamp(row))
471
+ rescue java.sql.SQLException
472
+ nil
473
+ end
474
+ when Jdbc::Types::TIME
475
+ to_ruby_time(resultset.getTime(row))
476
+ when Jdbc::Types::DATE
477
+ to_ruby_date(resultset.getDate(row))
478
+ when Jdbc::Types::LONGVARBINARY, Jdbc::Types::BLOB, Jdbc::Types::BINARY, Jdbc::Types::VARBINARY
479
+ resultset.getString(row)
480
+ else
481
+ raise "jdbc_adapter: type #{jdbc_type_name(type)} not supported yet"
327
482
  end
483
+ resultset.wasNull ? nil : value
484
+ end
485
+ def jdbc_type_name(type)
486
+ Jdbc::Types.constants.find {|t| Jdbc::Types.const_get(t.to_sym) == type}
328
487
  end
329
488
  end
330
489
 
331
490
  class JdbcAdapter < AbstractAdapter
491
+ ADAPTER_TYPES = {
492
+ /oracle/i => lambda{|cfg,adapt| adapt.extend(JdbcSpec::Oracle)},
493
+ /mimer/i => lambda{|cfg,adapt| adapt.extend(JdbcSpec::Mimer)},
494
+ /postgre/i => lambda{|cfg,adapt| adapt.extend(JdbcSpec::PostgreSQL)},
495
+ /mysql/i => lambda{|cfg,adapt| adapt.extend(JdbcSpec::MySQL)},
496
+ /sqlserver|tds/i => lambda{|cfg,adapt| adapt.extend(JdbcSpec::MsSQL)},
497
+ /hsqldb|\.h2\./i => lambda{|cfg,adapt| adapt.extend(JdbcSpec::HSQLDB)},
498
+ /derby/i => lambda{|cfg,adapt| adapt.extend(JdbcSpec::Derby)},
499
+ /db2/i => lambda{|cfg,adapt|
500
+ if cfg[:url] =~ /^jdbc:derby:net:/
501
+ adapt.extend(JdbcSpec::Derby)
502
+ else
503
+ adapt.extend(JdbcSpec::DB2)
504
+ end},
505
+ /firebird/i => lambda{|cfg,adapt| adapt.extend(JdbcSpec::FireBird)}
506
+
507
+ }
508
+
332
509
  def initialize(connection, logger, config)
333
510
  super(connection, logger)
334
511
  @config = config
335
- case config[:driver].to_s
336
- when /oracle/i: self.extend(JdbcSpec::Oracle)
337
- when /mimer/i: self.extend(JdbcSpec::Mimer)
338
- when /postgre/i: self.extend(JdbcSpec::PostgreSQL)
339
- when /mysql/i: self.extend(JdbcSpec::MySQL)
340
- when /sqlserver|tds/i: self.extend(JdbcSpec::MsSQL)
341
- when /hsqldb/i: self.extend(JdbcSpec::HSQLDB)
342
- when /derby/i: self.extend(JdbcSpec::Derby)
343
- when /db2/i:
344
- if config[:url] =~ /^jdbc:derby:net:/
345
- self.extend(JdbcSpec::Derby)
346
- else
347
- self.extend(JdbcSpec::DB2)
348
- end
349
- when /firebird/i: self.extend(JdbcSpec::FireBird)
512
+ ds = config[:driver].to_s
513
+ for reg, func in ADAPTER_TYPES
514
+ if reg === ds
515
+ func.call(@config,self)
516
+ end
350
517
  end
351
518
  end
352
519
 
353
520
  def modify_types(tp)
354
521
  tp
355
522
  end
356
-
523
+
357
524
  def adapter_name #:nodoc:
358
525
  'JDBC'
359
526
  end
@@ -400,7 +567,7 @@ module ActiveRecord
400
567
  end
401
568
  return nil,nil
402
569
  end
403
-
570
+
404
571
  def active?
405
572
  true
406
573
  end
@@ -439,7 +606,7 @@ module ActiveRecord
439
606
  end
440
607
 
441
608
  def columns(table_name, name = nil)
442
- @connection.columns(table_name)
609
+ @connection.columns(table_name.to_s)
443
610
  end
444
611
 
445
612
  def tables