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 +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)
|