ActiveRecord-JDBC 0.2.2 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
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