ActiveRecord-JDBC 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +10 -0
- data/Manifest.txt +15 -9
- data/Rakefile +59 -15
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +94 -281
- data/lib/jdbc_adapter.rb +5 -2
- data/lib/jdbc_adapter/jdbc_derby.rb +51 -13
- data/lib/jdbc_adapter/jdbc_mysql.rb +63 -18
- data/lib/jdbc_adapter/missing_functionality_helper.rb +72 -0
- data/lib/jdbc_adapter_internal.jar +0 -0
- data/test/db/derby.rb +2 -2
- data/test/db/jndi_config.rb +30 -0
- data/test/db/postgres.rb +10 -0
- data/test/derby_simple_test.rb +1 -5
- data/test/h2_simple_test.rb +1 -3
- data/test/hsqldb_simple_test.rb +1 -4
- data/test/jdbc_common.rb +6 -0
- data/test/jndi_test.rb +37 -0
- data/test/models/auto_id.rb +0 -1
- data/test/models/data_types.rb +18 -19
- data/test/models/entry.rb +0 -1
- data/test/mysql_simple_test.rb +1 -5
- data/test/postgres_simple_test.rb +12 -0
- data/test/simple.rb +2 -2
- metadata +17 -11
- data/lib/active_record/connection_adapters/jndi_adapter.rb +0 -51
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
|
-
|
20
|
-
|
21
|
-
|
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
|
-
|
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
|
-
|
30
|
-
|
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
|
-
|
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
|
-
|
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::
|
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
|
-
|
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['
|
87
|
-
|
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
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
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
|
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
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
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
|
-
|
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
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
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
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
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
|
-
|
423
|
-
|
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
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
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
|
-
|
441
|
-
|
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
|
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
|
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
|
-
|
591
|
-
|
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
|
-
|
599
|
-
|
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
|
-
|
603
|
-
|
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
|
-
|
443
|
+
execute(sql,name)
|
631
444
|
end
|
632
445
|
|
633
446
|
def log_no_bench(sql, name)
|