ActiveRecord-JDBC 0.2.3 → 0.2.4

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 CHANGED
@@ -1,3 +1,13 @@
1
+ == 0.2.4
2
+
3
+ * Release coincides with JRuby 0.9.9 release
4
+ * JRuby 0.9.9 is required
5
+ * MySQL close to 100% working
6
+ * Derby improvements
7
+ * DECIMAL/NUMERIC/FLOAT/REAL bugs fixed with type recognition for Oracle, Postgres, etc.
8
+ * HSQLDB has regressed this release and may not be functioning; we'll get it fixed for the
9
+ next one
10
+
1
11
  == 0.2.3
2
12
 
3
13
  * Release coincides (and compatible) with JRuby 0.9.8 release
data/Manifest.txt CHANGED
@@ -3,10 +3,8 @@ Manifest.txt
3
3
  README.txt
4
4
  Rakefile
5
5
  LICENSE
6
- lib/jdbc_adapter.rb
7
6
  lib/active_record/connection_adapters/jdbc_adapter.rb
8
7
  lib/active_record/connection_adapters/jdbc_adapter_spec.rb
9
- lib/active_record/connection_adapters/jndi_adapter.rb
10
8
  lib/jdbc_adapter/jdbc_db2.rb
11
9
  lib/jdbc_adapter/jdbc_derby.rb
12
10
  lib/jdbc_adapter/jdbc_firebird.rb
@@ -16,26 +14,34 @@ lib/jdbc_adapter/jdbc_mssql.rb
16
14
  lib/jdbc_adapter/jdbc_mysql.rb
17
15
  lib/jdbc_adapter/jdbc_oracle.rb
18
16
  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
17
+ lib/jdbc_adapter/missing_functionality_helper.rb
18
+ lib/jdbc_adapter.rb
19
+ lib/jdbc_adapter_internal.jar
26
20
  test/activerecord/connection_adapters/type_conversion_test.rb
27
21
  test/activerecord/connections/native_jdbc_mysql/connection.rb
28
22
  test/db/derby.rb
29
23
  test/db/h2.rb
30
24
  test/db/hsqldb.rb
25
+ test/db/jndi_config.rb
31
26
  test/db/logger.rb
32
27
  test/db/mysql.rb
28
+ test/db/postgres.rb
29
+ test/derby_simple_test.rb
30
+ test/h2_simple_test.rb
31
+ test/hsqldb_simple_test.rb
32
+ test/jdbc_common.rb
33
+ test/jndi_test.rb
34
+ test/manualTestDatabase.rb
33
35
  test/minirunit/testConnect.rb
34
36
  test/minirunit/testH2.rb
35
37
  test/minirunit/testHsqldb.rb
36
38
  test/minirunit/testLoadActiveRecord.rb
37
39
  test/minirunit/testMysql.rb
38
40
  test/minirunit/testRawSelect.rb
41
+ test/minirunit.rb
39
42
  test/models/auto_id.rb
40
43
  test/models/data_types.rb
41
44
  test/models/entry.rb
45
+ test/mysql_simple_test.rb
46
+ test/postgres_simple_test.rb
47
+ test/simple.rb
data/Rakefile CHANGED
@@ -3,9 +3,44 @@ require 'rake/testtask'
3
3
 
4
4
  task :default => :test
5
5
 
6
+ def java_classpath_arg # myriad of ways to discover JRuby classpath
7
+ begin
8
+ require 'java' # already running in a JRuby JVM
9
+ jruby_cpath = Java::java.lang.System.getProperty('java.class.path')
10
+ rescue LoadError
11
+ end
12
+ unless jruby_cpath
13
+ jruby_cpath = ENV['JRUBY_PARENT_CLASSPATH'] || ENV['JRUBY_HOME'] &&
14
+ FileList["#{ENV['JRUBY_HOME']}/lib/*.jar"].join(File::PATH_SEPARATOR)
15
+ end
16
+ cpath_arg = jruby_cpath ? "-cp #{jruby_cpath}" : ""
17
+ end
18
+
19
+ desc "Compile the native Java code."
20
+ task :java_compile do
21
+ mkdir_p "pkg/classes"
22
+ sh "javac -target 1.4 -source 1.4 -d pkg/classes #{java_classpath_arg} #{FileList['src/java/**/*.java'].join(' ')}"
23
+ sh "jar cf lib/jdbc_adapter_internal.jar -C pkg/classes/ ."
24
+ end
25
+ file "lib/jdbc_adapter_internal.jar" => :java_compile
26
+
27
+ task :more_clean do
28
+ rm_rf FileList['derby*']
29
+ rm_rf FileList['test.db.*']
30
+ rm_rf "test/reports"
31
+ rm_f FileList['lib/*.jar']
32
+ end
33
+
34
+ task :clean => :more_clean
35
+
36
+ task :filelist do
37
+ puts FileList['pkg/**/*'].inspect
38
+ end
39
+
6
40
  desc "Run AR-JDBC tests"
7
41
  if RUBY_PLATFORM =~ /java/
8
- task :test => [:test_mysql, :test_hsqldb, :test_derby]
42
+ # TODO: add more databases into the standard tests here.
43
+ task :test => [:java_compile, :test_mysql, :test_derby]
9
44
  else
10
45
  task :test => [:test_mysql]
11
46
  end
@@ -26,13 +61,30 @@ Rake::TestTask.new(:test_derby) do |t|
26
61
  t.libs << 'test'
27
62
  end
28
63
 
29
- begin
30
- require 'hoe'
64
+ Rake::TestTask.new(:test_postgresql) do |t|
65
+ t.test_files = FileList['test/postgres_simple_test.rb']
66
+ t.libs << 'test'
67
+ end
31
68
 
69
+ task :test_pgsql => [:test_postgresql]
70
+
71
+ Rake::TestTask.new(:test_jndi) do |t|
72
+ t.test_files = FileList['test/jndi_test.rb']
73
+ t.libs << 'test'
74
+ end
75
+
76
+ begin
32
77
  MANIFEST = FileList["History.txt", "Manifest.txt", "README.txt",
33
- "Rakefile", "LICENSE", "lib/**/*.rb", "test/**/*.rb"]
78
+ "Rakefile", "LICENSE", "lib/**/*.rb", "lib/jdbc_adapter_internal.jar", "test/**/*.rb"]
79
+
80
+ file "Manifest.txt" => :manifest
81
+ task :manifest do
82
+ File.open("Manifest.txt", "w") {|f| MANIFEST.each {|n| f << "#{n}\n"} }
83
+ end
84
+ Rake::Task['manifest'].invoke # Always regen manifest, so Hoe has up-to-date list of files
34
85
 
35
- Hoe.new("ActiveRecord-JDBC", "0.2.3") do |p|
86
+ require 'hoe'
87
+ Hoe.new("ActiveRecord-JDBC", "0.2.4") do |p|
36
88
  p.rubyforge_name = "jruby-extras"
37
89
  p.url = "http://jruby-extras.rubyforge.org/ActiveRecord-JDBC"
38
90
  p.author = "Nick Sieger, Ola Bini and JRuby contributors"
@@ -41,15 +93,7 @@ begin
41
93
  p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
42
94
  p.description = p.paragraphs_of('README.txt', 0...1).join("\n\n")
43
95
  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
96
  end
50
-
51
- task :package => :manifest
52
- rescue => e
53
- # Install hoe in order to make a release
54
- # puts e.inspect
97
+ rescue LoadError
98
+ puts "You really need Hoe installed to be able to package this gem"
55
99
  end
@@ -1,11 +1,14 @@
1
1
  require 'active_record/connection_adapters/abstract_adapter'
2
2
  require 'java'
3
3
  require 'active_record/connection_adapters/jdbc_adapter_spec'
4
+ require 'jdbc_adapter_internal'
5
+ require 'bigdecimal'
4
6
 
5
7
  module ActiveRecord
6
8
  class Base
7
9
  def self.jdbc_connection(config)
8
- ConnectionAdapters::JdbcAdapter.new(ConnectionAdapters::JdbcConnection.new(config), logger, config)
10
+ connection = ConnectionAdapters::JdbcConnection.new(config)
11
+ ConnectionAdapters::JdbcAdapter.new(connection, logger, config)
9
12
  end
10
13
 
11
14
  alias :attributes_with_quotes_pre_oracle :attributes_with_quotes
@@ -66,41 +69,46 @@ module ActiveRecord
66
69
  # type left. If all the selectors are applied and there is still more than one
67
70
  # type, an exception will be raised.
68
71
  AR_TO_JDBC_TYPES = {
69
- :string => [ lambda {|r| Jdbc::Types::VARCHAR == r['data_type']},
72
+ :string => [ lambda {|r| Jdbc::Types::VARCHAR == r['data_type'].to_i},
70
73
  lambda {|r| r['type_name'] =~ /^varchar/i},
71
74
  lambda {|r| r['type_name'] =~ /^varchar$/i},
72
75
  lambda {|r| r['type_name'] =~ /varying/i}],
73
- :text => [ lambda {|r| [Jdbc::Types::LONGVARCHAR, Jdbc::Types::CLOB].include?(r['data_type'])},
76
+ :text => [ lambda {|r| [Jdbc::Types::LONGVARCHAR, Jdbc::Types::CLOB].include?(r['data_type'].to_i)},
74
77
  lambda {|r| r['type_name'] =~ /^(text|clob)/i},
75
78
  lambda {|r| r['type_name'] =~ /^character large object$/i},
76
79
  lambda {|r| r['sql_data_type'] == 2005}],
77
- :integer => [ lambda {|r| Jdbc::Types::INTEGER == r['data_type']},
80
+ :integer => [ lambda {|r| Jdbc::Types::INTEGER == r['data_type'].to_i},
78
81
  lambda {|r| r['type_name'] =~ /^integer$/i},
79
82
  lambda {|r| r['type_name'] =~ /^int4$/i},
80
83
  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}],
83
- :float => [ lambda {|r| [Jdbc::Types::FLOAT,Jdbc::Types::DOUBLE].include?(r['data_type'])},
84
+ :decimal => [ lambda {|r| Jdbc::Types::DECIMAL == r['data_type'].to_i},
85
+ lambda {|r| r['type_name'] =~ /^decimal$/i},
86
+ lambda {|r| r['type_name'] =~ /^numeric$/i},
87
+ lambda {|r| r['type_name'] =~ /^number$/i},
88
+ lambda {|r| r['precision'] == '38'},
89
+ lambda {|r| r['data_type'] == '2'}],
90
+ :float => [ lambda {|r| [Jdbc::Types::FLOAT,Jdbc::Types::DOUBLE, Jdbc::Types::REAL].include?(r['data_type'].to_i)},
84
91
  lambda {|r| r['type_name'] =~ /^float/i},
85
92
  lambda {|r| r['type_name'] =~ /^double$/i},
86
- lambda {|r| r['precision'] == 15}],
87
- :datetime => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type']},
93
+ lambda {|r| r['type_name'] =~ /^real$/i},
94
+ lambda {|r| r['precision'] == '15'}],
95
+ :datetime => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
88
96
  lambda {|r| r['type_name'] =~ /^datetime/i},
89
97
  lambda {|r| r['type_name'] =~ /^timestamp$/i}],
90
- :timestamp => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type']},
98
+ :timestamp => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
91
99
  lambda {|r| r['type_name'] =~ /^timestamp$/i},
92
100
  lambda {|r| r['type_name'] =~ /^datetime/i} ],
93
- :time => [ lambda {|r| Jdbc::Types::TIME == r['data_type']},
101
+ :time => [ lambda {|r| Jdbc::Types::TIME == r['data_type'].to_i},
94
102
  lambda {|r| r['type_name'] =~ /^time$/i},
95
103
  lambda {|r| r['type_name'] =~ /^datetime$/i}],
96
- :date => [ lambda {|r| Jdbc::Types::DATE == r['data_type']},
104
+ :date => [ lambda {|r| Jdbc::Types::DATE == r['data_type'].to_i},
97
105
  lambda {|r| r['type_name'] =~ /^date$/i}],
98
- :binary => [ lambda {|r| [Jdbc::Types::LONGVARBINARY,Jdbc::Types::BINARY,Jdbc::Types::BLOB].include?(r['data_type'])},
106
+ :binary => [ lambda {|r| [Jdbc::Types::LONGVARBINARY,Jdbc::Types::BINARY,Jdbc::Types::BLOB].include?(r['data_type'].to_i)},
99
107
  lambda {|r| r['type_name'] =~ /^blob/i},
100
108
  lambda {|r| r['type_name'] =~ /sub_type 0$/i}, # For FireBird
101
109
  lambda {|r| r['type_name'] =~ /^varbinary$/i}, # We want this sucker for Mimer
102
110
  lambda {|r| r['type_name'] =~ /^binary$/i}, ],
103
- :boolean => [ lambda {|r| [Jdbc::Types::TINYINT].include?(r['data_type'])},
111
+ :boolean => [ lambda {|r| [Jdbc::Types::TINYINT].include?(r['data_type'].to_i)},
104
112
  lambda {|r| r['type_name'] =~ /^bool/i},
105
113
  lambda {|r| r['type_name'] =~ /^tinyint$/i},
106
114
  lambda {|r| r['type_name'] =~ /^decimal$/i}],
@@ -114,8 +122,8 @@ module ActiveRecord
114
122
  type_map = {}
115
123
  AR_TO_JDBC_TYPES.each_key do |k|
116
124
  typerow = choose_type(k)
117
- type_map[k] = { :name => typerow['type_name'] }
118
- type_map[k][:limit] = typerow['precision'] if [:integer, :string, :decimal].include?(k)
125
+ type_map[k] = { :name => typerow['type_name'].downcase }
126
+ type_map[k][:limit] = typerow['precision'] && typerow['precision'].to_i if [:integer, :string, :decimal].include?(k)
119
127
  type_map[k][:limit] = 1 if k == :boolean
120
128
  end
121
129
  type_map
@@ -129,7 +137,7 @@ module ActiveRecord
129
137
  return new_types.first if new_types.length == 1
130
138
  types = new_types if new_types.length > 0
131
139
  end
132
- raise "unable to choose type from: #{types.collect{|t| [t['type_name'],t]}.inspect} for #{ar_type}"
140
+ raise "unable to choose type from: #{types.collect{|t| [t['type_name'],t]}.inspect} for #{ar_type}"
133
141
  end
134
142
  end
135
143
 
@@ -146,8 +154,11 @@ module ActiveRecord
146
154
  end
147
155
 
148
156
  class JdbcColumn < Column
157
+ attr_writer :limit, :precision
158
+
149
159
  COLUMN_TYPES = {
150
160
  /oracle/i => lambda {|cfg,col| col.extend(JdbcSpec::Oracle::Column)},
161
+ /mysql/i => lambda {|cfg,col| col.extend(JdbcSpec::MySQL::Column)},
151
162
  /postgre/i => lambda {|cfg,col| col.extend(JdbcSpec::PostgreSQL::Column)},
152
163
  /sqlserver|tds/i => lambda {|cfg,col| col.extend(JdbcSpec::MsSQL::Column)},
153
164
  /hsqldb|\.h2\./i => lambda {|cfg,col| col.extend(JdbcSpec::HSQLDB::Column)},
@@ -168,6 +179,10 @@ module ActiveRecord
168
179
  end
169
180
  end
170
181
  super(name,default_value(default),*args)
182
+ init_column(name, default, *args)
183
+ end
184
+
185
+ def init_column(*args)
171
186
  end
172
187
 
173
188
  def default_value(val)
@@ -176,95 +191,26 @@ module ActiveRecord
176
191
  end
177
192
 
178
193
  class JdbcConnection
194
+ attr_reader :adapter
195
+
179
196
  def initialize(config)
180
- @config = config.symbolize_keys
181
- driver = @config[:driver].to_s
182
- user = @config[:username].to_s
183
- pass = @config[:password].to_s
184
- url = @config[:url].to_s
185
-
186
- unless driver && url
187
- raise ArgumentError, "jdbc adapter requires driver class and url"
197
+ @config = config.symbolize_keys!
198
+ if @config[:jndi]
199
+ configure_jndi
200
+ else
201
+ configure_jdbc
188
202
  end
189
-
190
- JdbcDriver.load(driver)
191
- @connection = Jdbc::DriverManager.getConnection(url, user, pass)
192
203
  set_native_database_types
193
-
194
204
  @stmts = {}
195
205
  rescue Exception => e
196
- raise "The driver encounter an error: #{e}"
197
- end
198
-
199
- def ps(sql)
200
- @connection.prepareStatement(sql)
201
- end
202
-
203
- def set_native_database_types
204
- types = unmarshal_result(@connection.getMetaData.getTypeInfo)
205
- @native_types = JdbcTypeConverter.new(types).choose_best_types
206
- end
207
-
208
- def native_database_types(adapt)
209
- types = {}
210
- @native_types.each_pair {|k,v| types[k] = v.inject({}) {|memo,kv| memo.merge({kv.first => (kv.last.dup rescue kv.last)})}}
211
- adapt.modify_types(types)
206
+ raise "The driver encountered an error: #{e}"
212
207
  end
213
-
214
- def columns(table_name, name = nil)
215
- metadata = @connection.getMetaData
216
- table_name.upcase! if metadata.storesUpperCaseIdentifiers
217
- table_name.downcase! if metadata.storesLowerCaseIdentifiers
218
- results = metadata.getColumns(nil, nil, table_name, nil)
219
- columns = []
220
- unmarshal_result(results).each do |col|
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')
233
- end
234
- columns
235
- rescue
236
- if @connection.is_closed
237
- reconnect!
238
- retry
239
- else
240
- raise
241
- end
242
- end
243
-
244
- def tables(&table_filter)
245
- metadata = @connection.getMetaData
246
- results = metadata.getTables(nil, nil, nil, nil)
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
208
+
209
+ def adapter=(adapt)
210
+ @adapter = adapt
211
+ @tps = {}
212
+ @native_types.each_pair {|k,v| @tps[k] = v.inject({}) {|memo,kv| memo.merge({kv.first => (kv.last.dup rescue kv.last)})}}
213
+ adapt.modify_types(@tps)
268
214
  end
269
215
 
270
216
  # Default JDBC introspection for index metadata on the JdbcConnection.
@@ -277,7 +223,14 @@ module ActiveRecord
277
223
  # should filter the return from this method instead.
278
224
  def indexes(table_name, name = nil)
279
225
  metadata = @connection.getMetaData
280
- resultset = metadata.getIndexInfo(nil, nil, table_name.to_s.upcase, false, false)
226
+ unless String === table_name
227
+ table_name = table_name.to_s
228
+ else
229
+ table_name = table_name.dup
230
+ end
231
+ table_name.upcase! if metadata.storesUpperCaseIdentifiers
232
+ table_name.downcase! if metadata.storesLowerCaseIdentifiers
233
+ resultset = metadata.getIndexInfo(nil, nil, table_name, false, false)
281
234
  primary_keys = primary_keys(table_name)
282
235
  indexes = []
283
236
  current_index = nil
@@ -311,180 +264,37 @@ module ActiveRecord
311
264
  end
312
265
  end
313
266
 
314
-
315
- def execute_insert(sql, pk)
316
- stmt = @connection.createStatement
317
- stmt.executeUpdate(sql,Jdbc::Statement::RETURN_GENERATED_KEYS)
318
- row = unmarshal_id_result(stmt.getGeneratedKeys)
319
- row.first && row.first.values.first
320
- rescue
321
- if @connection.is_closed
322
- reconnect!
323
- retry
324
- else
325
- raise
326
- end
327
- ensure
328
- stmt.close
329
- end
330
-
331
- def execute_update(sql)
332
- stmt = @connection.createStatement
333
- stmt.executeUpdate(sql)
334
- rescue
335
- if @connection.is_closed
336
- reconnect!
337
- retry
338
- else
339
- raise
340
- end
341
- ensure
342
- stmt.close
343
- end
344
-
345
- def execute_query(sql)
346
- stmt = @connection.createStatement
347
- unmarshal_result(stmt.executeQuery(sql))
348
- rescue
349
- if @connection.is_closed
350
- reconnect!
351
- retry
352
- else
353
- raise
354
- end
355
- ensure
356
- stmt.close
357
- end
358
-
359
- def begin
360
- @connection.setAutoCommit(false)
361
- end
362
-
363
- def commit
364
- @connection.commit
365
- ensure
366
- @connection.setAutoCommit(true)
367
- end
368
-
369
- def rollback
370
- @connection.rollback
371
- ensure
372
- @connection.setAutoCommit(true)
373
- end
374
-
375
267
  private
376
- def unmarshal_result(resultset, &row_filter)
377
- metadata = resultset.getMetaData
378
- column_count = metadata.getColumnCount
379
- column_names = ['']
380
- column_types = ['']
381
- column_scale = ['']
382
-
383
- 1.upto(column_count) do |i|
384
- column_names << metadata.getColumnName(i)
385
- column_types << metadata.getColumnType(i)
386
- column_scale << metadata.getScale(i)
268
+ def configure_jndi
269
+ jndi = @config[:jndi].to_s
270
+ ctx = javax.naming.InitialContext.new
271
+ ds = ctx.lookup(jndi)
272
+ set_connection ds.connection
273
+ unless @config[:driver]
274
+ @config[:driver] = @connection.meta_data.connection.java_class.name
387
275
  end
388
-
389
- results = []
390
-
391
- # take all rows if block not supplied
392
- row_filter = lambda{|result_row| true} unless block_given?
393
-
394
- while resultset.next
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
403
- end
404
- end
405
-
406
- results
407
276
  end
408
277
 
409
- def unmarshal_id_result(resultset)
410
- metadata = resultset.getMetaData
411
- column_count = metadata.getColumnCount
412
- column_types = ['']
413
- column_scale = ['']
414
-
415
- 1.upto(column_count) do |i|
416
- column_types << metadata.getColumnType(i)
417
- column_scale << metadata.getScale(i)
418
- end
419
-
420
- results = []
278
+ def configure_jdbc
279
+ driver = @config[:driver].to_s
280
+ user = @config[:username].to_s
281
+ pass = @config[:password].to_s
282
+ url = @config[:url].to_s
421
283
 
422
- while resultset.next
423
- row = {}
424
- 1.upto(column_count) do |i|
425
- row[i] = row[i.to_s] = convert_jdbc_type_to_ruby(i, column_types[i], column_scale[i], resultset)
426
- end
427
- results << row
284
+ unless driver && url
285
+ raise ArgumentError, "jdbc adapter requires driver class and url"
428
286
  end
429
-
430
- results
431
- end
432
-
433
- def to_ruby_time(java_time)
434
- if java_time
435
- tm = java_time.getTime
436
- Time.at(tm / 1000, (tm % 1000) * 1000)
287
+
288
+ if driver =~ /mysql/i
289
+ div = url =~ /\?/ ? '&' : '?'
290
+ url = "#{url}#{div}zeroDateTimeBehavior=convertToNull&jdbcCompliantTruncation=false"
291
+ @config[:url] = url
437
292
  end
438
- end
439
293
 
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
294
+ JdbcDriver.load(driver)
295
+ set_connection Jdbc::DriverManager.getConnection(url, user, pass)
446
296
  end
447
297
 
448
- def convert_jdbc_type_to_ruby(row, type, scale, resultset)
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)
455
- else
456
- resultset.getLong(row)
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"
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}
487
- end
488
298
  end
489
299
 
490
300
  class JdbcAdapter < AbstractAdapter
@@ -515,6 +325,7 @@ module ActiveRecord
515
325
  func.call(@config,self)
516
326
  end
517
327
  end
328
+ connection.adapter = self
518
329
  end
519
330
 
520
331
  def modify_types(tp)
@@ -529,10 +340,14 @@ module ActiveRecord
529
340
  true
530
341
  end
531
342
 
532
- def native_database_types #:nodoc
533
- @connection.native_database_types(self)
343
+ def native_database_types #:nodoc:
344
+ @connection.native_database_types
534
345
  end
535
346
 
347
+ def database_name #:nodoc:
348
+ @connection.database_name
349
+ end
350
+
536
351
  def native_sql_to_type(tp)
537
352
  if /^(.*?)\(([0-9]+)\)/ =~ tp
538
353
  tname = $1
@@ -568,13 +383,9 @@ module ActiveRecord
568
383
  return nil,nil
569
384
  end
570
385
 
571
- def active?
572
- true
573
- end
574
-
575
386
  def reconnect!
576
387
  @connection.close rescue nil
577
- @connection = JdbcConnection.new(@config,self)
388
+ @connection = JdbcConnection.new(@config)
578
389
  end
579
390
 
580
391
  def select_all(sql, name = nil)
@@ -587,22 +398,24 @@ module ActiveRecord
587
398
 
588
399
  def execute(sql, name = nil)
589
400
  log_no_bench(sql, name) do
590
- if sql =~ /^(select|show)/i
591
- @connection.execute_query(sql)
401
+ case sql.strip
402
+ when /^(select|show)/i:
403
+ @connection.execute_query(sql)
404
+ when /^insert/i:
405
+ @connection.execute_insert(sql)
592
406
  else
593
407
  @connection.execute_update(sql)
594
408
  end
595
409
  end
596
410
  end
597
411
 
598
- alias :update :execute
599
- alias :delete :execute
412
+ def update(sql, name = nil) #:nodoc:
413
+ execute(sql, name)
414
+ end
600
415
 
601
416
  def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
602
- log_no_bench(sql, name) do
603
- id = @connection.execute_insert(sql, pk)
604
- id_value || id
605
- end
417
+ id = execute(sql, name = nil)
418
+ id_value || id
606
419
  end
607
420
 
608
421
  def columns(table_name, name = nil)
@@ -627,7 +440,7 @@ module ActiveRecord
627
440
 
628
441
  private
629
442
  def select(sql, name=nil)
630
- log_no_bench(sql, name) { @connection.execute_query(sql) }
443
+ execute(sql,name)
631
444
  end
632
445
 
633
446
  def log_no_bench(sql, name)