activerecord-jdbc-adapter 0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +61 -0
- data/LICENSE +21 -0
- data/Manifest.txt +64 -0
- data/README.txt +116 -0
- data/Rakefile +146 -0
- data/lib/active_record/connection_adapters/derby_adapter.rb +13 -0
- data/lib/active_record/connection_adapters/h2_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/hsqldb_adapter.rb +13 -0
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +575 -0
- data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +10 -0
- data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mysql_adapter.rb +13 -0
- data/lib/active_record/connection_adapters/oracle_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/postgresql_adapter.rb +13 -0
- data/lib/jdbc_adapter.rb +32 -0
- data/lib/jdbc_adapter/jdbc_db2.rb +104 -0
- data/lib/jdbc_adapter/jdbc_derby.rb +362 -0
- data/lib/jdbc_adapter/jdbc_firebird.rb +109 -0
- data/lib/jdbc_adapter/jdbc_hsqldb.rb +168 -0
- data/lib/jdbc_adapter/jdbc_mimer.rb +134 -0
- data/lib/jdbc_adapter/jdbc_mssql.rb +356 -0
- data/lib/jdbc_adapter/jdbc_mysql.rb +168 -0
- data/lib/jdbc_adapter/jdbc_oracle.rb +340 -0
- data/lib/jdbc_adapter/jdbc_postgre.rb +347 -0
- data/lib/jdbc_adapter/missing_functionality_helper.rb +72 -0
- data/lib/jdbc_adapter/version.rb +5 -0
- data/lib/jdbc_adapter_internal.jar +0 -0
- data/lib/tasks/jdbc_databases.rake +72 -0
- data/src/java/JDBCDerbySpec.java +323 -0
- data/src/java/JDBCMySQLSpec.java +89 -0
- data/src/java/JdbcAdapterInternalService.java +953 -0
- data/test/activerecord/connection_adapters/type_conversion_test.rb +31 -0
- data/test/activerecord/connections/native_jdbc_mysql/connection.rb +25 -0
- data/test/db/derby.rb +18 -0
- data/test/db/h2.rb +11 -0
- data/test/db/hsqldb.rb +15 -0
- data/test/db/jdbc.rb +11 -0
- data/test/db/jndi_config.rb +30 -0
- data/test/db/logger.rb +3 -0
- data/test/db/mysql.rb +9 -0
- data/test/db/postgres.rb +9 -0
- data/test/derby_multibyte_test.rb +12 -0
- data/test/derby_simple_test.rb +12 -0
- data/test/generic_jdbc_connection_test.rb +9 -0
- data/test/h2_simple_test.rb +7 -0
- data/test/hsqldb_simple_test.rb +6 -0
- data/test/jdbc_adapter/jdbc_db2_test.rb +21 -0
- data/test/jdbc_common.rb +6 -0
- data/test/jndi_test.rb +37 -0
- data/test/manualTestDatabase.rb +195 -0
- data/test/minirunit.rb +109 -0
- data/test/minirunit/testConnect.rb +14 -0
- data/test/minirunit/testH2.rb +73 -0
- data/test/minirunit/testHsqldb.rb +73 -0
- data/test/minirunit/testLoadActiveRecord.rb +3 -0
- data/test/minirunit/testMysql.rb +83 -0
- data/test/minirunit/testRawSelect.rb +24 -0
- data/test/models/auto_id.rb +18 -0
- data/test/models/data_types.rb +18 -0
- data/test/models/entry.rb +20 -0
- data/test/mysql_multibyte_test.rb +6 -0
- data/test/mysql_simple_test.rb +13 -0
- data/test/postgres_simple_test.rb +12 -0
- data/test/simple.rb +157 -0
- metadata +112 -0
data/History.txt
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
== 0.6
|
2
|
+
|
3
|
+
- Gem is renamed to "activerecord-jdbc-adapter" to follow new conventions introduced in Rails 2.0 for third-party adapters. Rails 2.0 compatibility is introduced.
|
4
|
+
- Add dependency on ActiveRecord >= 1.14 (from the Rails 1.1.x release)
|
5
|
+
- New drivers (jdbc-XXX) and adapter (activerecord-jdbcXXX-adapter) gems available separately. See the README.txt file for details.
|
6
|
+
- Plain "jdbc" driver is still available if you want to use the full driver/url way of specifying the driver.
|
7
|
+
- More bugfixes to Oracle and SQLServer courtesy of Ola & ThoughtWorks
|
8
|
+
|
9
|
+
== 0.5
|
10
|
+
|
11
|
+
- Release coincides with JRuby 1.0.1 release
|
12
|
+
- It is no longer necessary to specify :driver and :url configuration parameters for the mysql,
|
13
|
+
postgresql, oracle, derby, hsqldb, and h2 adapters. The previous configuration is still
|
14
|
+
valid and compatible, but for new applications, this makes it possible to use the exact same
|
15
|
+
database.yml configuration as Rails applications running under native Ruby.
|
16
|
+
- JDBC drivers can now be dynamically loaded by Ruby code, without being on the classpath prior to
|
17
|
+
launching JRuby. Simply use "require 'jdbc-driver.jar'" in JRuby code to add it to the runtime
|
18
|
+
classpath.
|
19
|
+
- Updates to HSQL, MS SQLServer, Postgres, Oracle and Derby adapters
|
20
|
+
|
21
|
+
== 0.4
|
22
|
+
|
23
|
+
- Release coincides with JRuby 1.0 release
|
24
|
+
- Shoring up PostgreSQL (courtesy Dudley Flanders) and HSQL (courtesy Matthew Williams)
|
25
|
+
- Fix timestamps on Oracle to use DATE (as everything else)
|
26
|
+
- Derby fixes: Fix for open result set issue, better structure dump, quoting, column type changing
|
27
|
+
- Sybase type recognition fix (courtesy Dean Mao)
|
28
|
+
|
29
|
+
== 0.3.1
|
30
|
+
|
31
|
+
* Derby critical fixes shortly after 0.3
|
32
|
+
|
33
|
+
== 0.3
|
34
|
+
|
35
|
+
* Release coincides with JRuby 1.0.0RC1 release
|
36
|
+
* Improvements for Derby, Postgres, and Oracle, all of which are running
|
37
|
+
> 95% of AR tests
|
38
|
+
|
39
|
+
== 0.2.4
|
40
|
+
|
41
|
+
* Release coincides with JRuby 0.9.9 release
|
42
|
+
* JRuby 0.9.9 is required
|
43
|
+
* MySQL close to 100% working
|
44
|
+
* Derby improvements
|
45
|
+
* DECIMAL/NUMERIC/FLOAT/REAL bugs fixed with type recognition for Oracle, Postgres, etc.
|
46
|
+
* HSQLDB has regressed this release and may not be functioning; we'll get it fixed for the
|
47
|
+
next one
|
48
|
+
|
49
|
+
== 0.2.3
|
50
|
+
|
51
|
+
* Release coincides (and compatible) with JRuby 0.9.8 release
|
52
|
+
* 8 bugs fixed: see http://rubyurl.com/0Da
|
53
|
+
* Improvements and compatibility fixes for Rails 1.2.x
|
54
|
+
|
55
|
+
== 0.2.1, 0.2.2
|
56
|
+
|
57
|
+
* Early releases, added better support for multiple databases
|
58
|
+
|
59
|
+
== 0.0.1
|
60
|
+
|
61
|
+
* Initial, very alpha release
|
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2006-2007 Nick Sieger <nick@nicksieger.com>
|
2
|
+
Copyright (c) 2006-2007 Ola Bini <ola@ologix.com>
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/Manifest.txt
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
History.txt
|
2
|
+
Manifest.txt
|
3
|
+
README.txt
|
4
|
+
Rakefile
|
5
|
+
LICENSE
|
6
|
+
lib/active_record/connection_adapters/derby_adapter.rb
|
7
|
+
lib/active_record/connection_adapters/h2_adapter.rb
|
8
|
+
lib/active_record/connection_adapters/hsqldb_adapter.rb
|
9
|
+
lib/active_record/connection_adapters/jdbc_adapter.rb
|
10
|
+
lib/active_record/connection_adapters/jdbc_adapter_spec.rb
|
11
|
+
lib/active_record/connection_adapters/jndi_adapter.rb
|
12
|
+
lib/active_record/connection_adapters/mysql_adapter.rb
|
13
|
+
lib/active_record/connection_adapters/oracle_adapter.rb
|
14
|
+
lib/active_record/connection_adapters/postgresql_adapter.rb
|
15
|
+
lib/jdbc_adapter/jdbc_db2.rb
|
16
|
+
lib/jdbc_adapter/jdbc_derby.rb
|
17
|
+
lib/jdbc_adapter/jdbc_firebird.rb
|
18
|
+
lib/jdbc_adapter/jdbc_hsqldb.rb
|
19
|
+
lib/jdbc_adapter/jdbc_mimer.rb
|
20
|
+
lib/jdbc_adapter/jdbc_mssql.rb
|
21
|
+
lib/jdbc_adapter/jdbc_mysql.rb
|
22
|
+
lib/jdbc_adapter/jdbc_oracle.rb
|
23
|
+
lib/jdbc_adapter/jdbc_postgre.rb
|
24
|
+
lib/jdbc_adapter/missing_functionality_helper.rb
|
25
|
+
lib/jdbc_adapter/version.rb
|
26
|
+
lib/jdbc_adapter.rb
|
27
|
+
lib/jdbc_adapter_internal.jar
|
28
|
+
test/activerecord/connection_adapters/type_conversion_test.rb
|
29
|
+
test/activerecord/connections/native_jdbc_mysql/connection.rb
|
30
|
+
test/db/derby.rb
|
31
|
+
test/db/h2.rb
|
32
|
+
test/db/hsqldb.rb
|
33
|
+
test/db/jdbc.rb
|
34
|
+
test/db/jndi_config.rb
|
35
|
+
test/db/logger.rb
|
36
|
+
test/db/mysql.rb
|
37
|
+
test/db/postgres.rb
|
38
|
+
test/derby_multibyte_test.rb
|
39
|
+
test/derby_simple_test.rb
|
40
|
+
test/generic_jdbc_connection_test.rb
|
41
|
+
test/h2_simple_test.rb
|
42
|
+
test/hsqldb_simple_test.rb
|
43
|
+
test/jdbc_adapter/jdbc_db2_test.rb
|
44
|
+
test/jdbc_common.rb
|
45
|
+
test/jndi_test.rb
|
46
|
+
test/manualTestDatabase.rb
|
47
|
+
test/minirunit/testConnect.rb
|
48
|
+
test/minirunit/testH2.rb
|
49
|
+
test/minirunit/testHsqldb.rb
|
50
|
+
test/minirunit/testLoadActiveRecord.rb
|
51
|
+
test/minirunit/testMysql.rb
|
52
|
+
test/minirunit/testRawSelect.rb
|
53
|
+
test/minirunit.rb
|
54
|
+
test/models/auto_id.rb
|
55
|
+
test/models/data_types.rb
|
56
|
+
test/models/entry.rb
|
57
|
+
test/mysql_multibyte_test.rb
|
58
|
+
test/mysql_simple_test.rb
|
59
|
+
test/postgres_simple_test.rb
|
60
|
+
test/simple.rb
|
61
|
+
lib/tasks/jdbc_databases.rake
|
62
|
+
src/java/JdbcAdapterInternalService.java
|
63
|
+
src/java/JDBCDerbySpec.java
|
64
|
+
src/java/JDBCMySQLSpec.java
|
data/README.txt
ADDED
@@ -0,0 +1,116 @@
|
|
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 jruby-extras mailing-list[http://rubyforge.org/mail/?group_id=2014] to help us discover support for more databases.
|
30
|
+
|
31
|
+
== Using ActiveRecord JDBC
|
32
|
+
|
33
|
+
=== Inside Rails
|
34
|
+
|
35
|
+
To use ActiveRecord-JDBC with JRuby on Rails:
|
36
|
+
|
37
|
+
1. Choose the adapter you wish to gem install. The following pre-packaged adapters are available:
|
38
|
+
|
39
|
+
* base jdbc (<tt>activerecord-jdbc-adapter</tt>). Supports all available databases via JDBC, but requires you to download and manually install the database vendor's JDBC driver .jar file.
|
40
|
+
* mysql (<tt>activerecord-jdbcmysql-adapter</tt>)
|
41
|
+
* postgresql (<tt>activerecord-jdbcpostgresql-adapter</tt>)
|
42
|
+
* derby (<tt>activerecord-jdbcderby-adapter</tt>)
|
43
|
+
* hsqldb (<tt>activerecord-jdbchsqldb-adapter</tt>)
|
44
|
+
|
45
|
+
2. If you're using Rails 2.0, you may skip to the next step. For Rails prior to version 2.0, you'll need to 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>. (If you're using ActiveRecord-JDBC under the old gem name used in versions 0.5 and earlier, replace 'activerecord-jdbc-adapter' with 'ActiveRecord-JDBC' below.)
|
46
|
+
|
47
|
+
if RUBY_PLATFORM =~ /java/
|
48
|
+
require 'rubygems'
|
49
|
+
gem 'activerecord-jdbc-adapter'
|
50
|
+
require 'jdbc_adapter'
|
51
|
+
end
|
52
|
+
|
53
|
+
3. Configure your database.yml to use the <code>jdbc</code> adapter.
|
54
|
+
For mysql, postgres, derby, oracle, hsqldb and h2 you can simply configure the database in the normal Rails style. If you use one of the convenience 'activerecord-jdbcXXX-adapter' adapters, be sure and put a 'jdbc' prefix in front of the databas adapter name as below.
|
55
|
+
|
56
|
+
development:
|
57
|
+
adapter: jdbcmysql
|
58
|
+
username: blog
|
59
|
+
password:
|
60
|
+
hostname: localhost
|
61
|
+
database: weblog_development
|
62
|
+
|
63
|
+
For other databases, you'll need to know the database driver class and URL. Example:
|
64
|
+
|
65
|
+
development:
|
66
|
+
adapter: jdbc
|
67
|
+
username: blog
|
68
|
+
password:
|
69
|
+
driver: com.mysql.jdbc.Driver
|
70
|
+
url: jdbc:mysql://localhost:3306/weblog_development
|
71
|
+
|
72
|
+
=== Standalone, with ActiveRecord
|
73
|
+
|
74
|
+
1. Install the gem with JRuby:
|
75
|
+
|
76
|
+
jruby -S gem install activerecord-jdbc-adapter
|
77
|
+
|
78
|
+
If you wish to use the adapter for a specific database, you can install it directly and a driver gem will be installed as well:
|
79
|
+
|
80
|
+
jruby -S gem install activerecord-jdbcderby-adapter
|
81
|
+
|
82
|
+
2. If using ActiveRecord 2.0 (Rails 2.0) or greater, you can skip to the next step. Otherwise, ensure the following code gets executed in your script:
|
83
|
+
|
84
|
+
require 'rubygems'
|
85
|
+
gem 'activerecord-jdbc-adapter'
|
86
|
+
require 'jdbc_adapter'
|
87
|
+
require 'active_record'
|
88
|
+
|
89
|
+
3. After this you can establish a JDBC connection like this:
|
90
|
+
|
91
|
+
ActiveRecord::Base.establish_connection(
|
92
|
+
:adapter => 'jdbcderby',
|
93
|
+
:database => "db/my-database"
|
94
|
+
)
|
95
|
+
|
96
|
+
or like this (but requires that you manually put the driver jar on the classpath):
|
97
|
+
|
98
|
+
ActiveRecord::Base.establish_connection(
|
99
|
+
:adapter => 'jdbc',
|
100
|
+
:driver => 'org.apache.derby.jdbc.EmbeddedDriver',
|
101
|
+
:url => 'jdbc:derby:test_ar;create=true'
|
102
|
+
)
|
103
|
+
|
104
|
+
== Running AR-JDBC's Tests
|
105
|
+
|
106
|
+
Drivers for 4 open-source databases are included. Provided you have MySQL installed, you can simply type <tt>jruby -S rake</tt> to run the tests. A database named <tt>weblog_development</tt> is needed beforehand with a connection user of "blog" and password empty.
|
107
|
+
|
108
|
+
== Authors
|
109
|
+
|
110
|
+
This project was written by Nick Sieger <nick@nicksieger.com> and Ola Bini <ola@ologix.com> with lots of help from the JRuby community.
|
111
|
+
|
112
|
+
== License
|
113
|
+
|
114
|
+
ActiveRecord-JDBC is released under a BSD license. See the LICENSE file included with the distribution for details.
|
115
|
+
|
116
|
+
Open-source driver gems for ActiveRecord JDBC are licensed under the same license the database's drivers are licensed. See each driver gem's LICENSE.txt file for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,146 @@
|
|
1
|
+
require 'rake'
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
task :default => [:java_compile, :test]
|
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
|
+
|
40
|
+
if RUBY_PLATFORM =~ /java/
|
41
|
+
# TODO: add more databases into the standard tests here.
|
42
|
+
task :test => [:test_mysql, :test_jdbc, :test_derby, :test_hsqldb]
|
43
|
+
else
|
44
|
+
task :test => [:test_mysql]
|
45
|
+
end
|
46
|
+
|
47
|
+
FileList['drivers/*'].each do |d|
|
48
|
+
next unless File.directory?(d)
|
49
|
+
driver = File.basename(d)
|
50
|
+
Rake::TestTask.new("test_#{driver}") do |t|
|
51
|
+
files = FileList["test/#{driver}*test.rb"]
|
52
|
+
if driver == "derby"
|
53
|
+
files << 'test/activerecord/connection_adapters/type_conversion_test.rb'
|
54
|
+
end
|
55
|
+
t.ruby_opts << "-rjdbc/#{driver}"
|
56
|
+
t.test_files = files
|
57
|
+
t.libs << "test" << "#{d}/lib"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
Rake::TestTask.new(:test_jdbc) do |t|
|
62
|
+
t.test_files = FileList['test/generic_jdbc_connection_test.rb']
|
63
|
+
t.libs << 'test' << 'drivers/mysql/lib'
|
64
|
+
end
|
65
|
+
|
66
|
+
Rake::TestTask.new(:test_jndi) do |t|
|
67
|
+
t.test_files = FileList['test/jndi_test.rb']
|
68
|
+
t.libs << 'test' << 'drivers/derby/lib'
|
69
|
+
end
|
70
|
+
|
71
|
+
task :test_postgresql => [:test_postgres]
|
72
|
+
task :test_pgsql => [:test_postgres]
|
73
|
+
|
74
|
+
MANIFEST = FileList["History.txt", "Manifest.txt", "README.txt",
|
75
|
+
"Rakefile", "LICENSE", "lib/**/*.rb", "lib/jdbc_adapter_internal.jar", "test/**/*.rb",
|
76
|
+
"lib/**/*.rake", "src/**/*.java"]
|
77
|
+
|
78
|
+
file "Manifest.txt" => :manifest
|
79
|
+
task :manifest do
|
80
|
+
File.open("Manifest.txt", "w") {|f| MANIFEST.each {|n| f << "#{n}\n"} }
|
81
|
+
end
|
82
|
+
Rake::Task['manifest'].invoke # Always regen manifest, so Hoe has up-to-date list of files
|
83
|
+
|
84
|
+
require File.dirname(__FILE__) + "/lib/jdbc_adapter/version"
|
85
|
+
begin
|
86
|
+
require 'hoe'
|
87
|
+
Hoe.new("activerecord-jdbc-adapter", JdbcAdapter::Version::VERSION) do |p|
|
88
|
+
p.rubyforge_name = "jruby-extras"
|
89
|
+
p.url = "http://jruby-extras.rubyforge.org/activerecord-jdbc-adapter"
|
90
|
+
p.author = "Nick Sieger, Ola Bini and JRuby contributors"
|
91
|
+
p.email = "nick@nicksieger.com, ola.bini@gmail.com"
|
92
|
+
p.summary = "JDBC adapter for ActiveRecord, for use within JRuby on Rails."
|
93
|
+
p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
|
94
|
+
p.description = p.paragraphs_of('README.txt', 0...1).join("\n\n")
|
95
|
+
end.spec.dependencies.delete_if { |dep| dep.name == "hoe" }
|
96
|
+
rescue LoadError
|
97
|
+
puts "You really need Hoe installed to be able to package this gem"
|
98
|
+
rescue => e
|
99
|
+
puts "ignoring error while loading hoe: #{e.to_s}"
|
100
|
+
end
|
101
|
+
|
102
|
+
def rake(*args)
|
103
|
+
ruby "-S", "rake", *args
|
104
|
+
end
|
105
|
+
|
106
|
+
%w(test package install_gem release clean).each do |task|
|
107
|
+
desc "Run rake #{task} on all available adapters and drivers"
|
108
|
+
task "all:#{task}" => task
|
109
|
+
end
|
110
|
+
|
111
|
+
(Dir["drivers/*/Rakefile"] + Dir["adapters/*/Rakefile"]).each do |rakefile|
|
112
|
+
dir = File.dirname(rakefile)
|
113
|
+
prefix = dir.sub(%r{/}, ':')
|
114
|
+
tasks = %w(package install_gem debug_gem clean)
|
115
|
+
tasks << "test" if File.directory?(File.join(dir, "test"))
|
116
|
+
tasks.each do |task|
|
117
|
+
desc "Run rake #{task} on #{dir}"
|
118
|
+
task "#{prefix}:#{task}" do
|
119
|
+
Dir.chdir(dir) do
|
120
|
+
rake task
|
121
|
+
end
|
122
|
+
end
|
123
|
+
task "#{File.dirname(dir)}:#{task}" => "#{prefix}:#{task}"
|
124
|
+
task "all:#{task}" => "#{prefix}:#{task}"
|
125
|
+
end
|
126
|
+
desc "Run rake release on #{dir}"
|
127
|
+
task "#{prefix}:release" do
|
128
|
+
Dir.chdir(dir) do
|
129
|
+
version = nil
|
130
|
+
if dir =~ /adapters/
|
131
|
+
version = ENV['VERSION']
|
132
|
+
else
|
133
|
+
Dir["lib/**/*.rb"].each do |file|
|
134
|
+
version ||= File.open(file) {|f| f.read =~ /VERSION = "([^"]+)"/ && $1}
|
135
|
+
end
|
136
|
+
end
|
137
|
+
rake "release", "VERSION=#{version}"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
# Only release adapters synchronously with main release. Drivers are versioned
|
141
|
+
# according to their JDBC driver versions.
|
142
|
+
if dir =~ /adapters/
|
143
|
+
task "adapters:release" => "#{prefix}:release"
|
144
|
+
task "all:release" => "#{prefix}:release"
|
145
|
+
end
|
146
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
tried_gem = false
|
2
|
+
begin
|
3
|
+
require "jdbc/derby"
|
4
|
+
rescue LoadError
|
5
|
+
unless tried_gem
|
6
|
+
require 'rubygems'
|
7
|
+
gem "jdbc-derby"
|
8
|
+
tried_gem = true
|
9
|
+
retry
|
10
|
+
end
|
11
|
+
# trust that the derby jar is already present
|
12
|
+
end
|
13
|
+
require 'active_record/connection_adapters/jdbc_adapter'
|
@@ -0,0 +1 @@
|
|
1
|
+
require 'active_record/connection_adapters/jdbc_adapter'
|
@@ -0,0 +1,13 @@
|
|
1
|
+
tried_gem = false
|
2
|
+
begin
|
3
|
+
require "jdbc/hsqldb"
|
4
|
+
rescue LoadError
|
5
|
+
unless tried_gem
|
6
|
+
require 'rubygems'
|
7
|
+
gem "jdbc-hsqldb"
|
8
|
+
tried_gem = true
|
9
|
+
retry
|
10
|
+
end
|
11
|
+
# trust that the hsqldb jar is already present
|
12
|
+
end
|
13
|
+
require 'active_record/connection_adapters/jdbc_adapter'
|
@@ -0,0 +1,575 @@
|
|
1
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
2
|
+
require 'java'
|
3
|
+
require 'active_record/connection_adapters/jdbc_adapter_spec'
|
4
|
+
require 'jdbc_adapter_internal'
|
5
|
+
require 'bigdecimal'
|
6
|
+
|
7
|
+
module ActiveRecord
|
8
|
+
module ConnectionAdapters # :nodoc:
|
9
|
+
module SchemaStatements
|
10
|
+
# The original implementation of this had a bug, which modifies native_database_types.
|
11
|
+
# This version allows us to cache that value.
|
12
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil) #:nodoc:
|
13
|
+
native = native_database_types[type]
|
14
|
+
column_type_sql = native.is_a?(Hash) ? native[:name] : native
|
15
|
+
if type == :decimal # ignore limit, use precison and scale
|
16
|
+
precision ||= native[:precision]
|
17
|
+
scale ||= native[:scale]
|
18
|
+
if precision
|
19
|
+
if scale
|
20
|
+
column_type_sql += "(#{precision},#{scale})"
|
21
|
+
else
|
22
|
+
column_type_sql += "(#{precision})"
|
23
|
+
end
|
24
|
+
else
|
25
|
+
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified" if scale
|
26
|
+
end
|
27
|
+
column_type_sql
|
28
|
+
else
|
29
|
+
limit ||= native[:limit]
|
30
|
+
column_type_sql += "(#{limit})" if limit
|
31
|
+
column_type_sql
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
module JdbcSpec
|
39
|
+
module ActiveRecordExtensions
|
40
|
+
def jdbc_connection(config)
|
41
|
+
connection = ::ActiveRecord::ConnectionAdapters::JdbcConnection.new(config)
|
42
|
+
::ActiveRecord::ConnectionAdapters::JdbcAdapter.new(connection, logger, config)
|
43
|
+
end
|
44
|
+
alias jndi_connection jdbc_connection
|
45
|
+
|
46
|
+
def embedded_driver(config)
|
47
|
+
config[:username] ||= "sa"
|
48
|
+
config[:password] ||= ""
|
49
|
+
jdbc_connection(config)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
module ActiveRecord
|
55
|
+
class Base
|
56
|
+
extend JdbcSpec::ActiveRecordExtensions
|
57
|
+
|
58
|
+
alias :attributes_with_quotes_pre_oracle :attributes_with_quotes
|
59
|
+
def attributes_with_quotes(include_primary_key = true) #:nodoc:
|
60
|
+
aq = attributes_with_quotes_pre_oracle(include_primary_key)
|
61
|
+
if connection.class == ConnectionAdapters::JdbcAdapter && (connection.is_a?(JdbcSpec::Oracle) || connection.is_a?(JdbcSpec::Mimer))
|
62
|
+
aq[self.class.primary_key] = "?" if include_primary_key && aq[self.class.primary_key].nil?
|
63
|
+
end
|
64
|
+
aq
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
module ConnectionAdapters
|
69
|
+
module Java
|
70
|
+
Class = java.lang.Class
|
71
|
+
URL = java.net.URL
|
72
|
+
URLClassLoader = java.net.URLClassLoader
|
73
|
+
end
|
74
|
+
|
75
|
+
module Jdbc
|
76
|
+
Mutex = java.lang.Object.new
|
77
|
+
DriverManager = java.sql.DriverManager
|
78
|
+
Statement = java.sql.Statement
|
79
|
+
Types = java.sql.Types
|
80
|
+
|
81
|
+
# some symbolic constants for the benefit of the JDBC-based
|
82
|
+
# JdbcConnection#indexes method
|
83
|
+
module IndexMetaData
|
84
|
+
INDEX_NAME = 6
|
85
|
+
NON_UNIQUE = 4
|
86
|
+
TABLE_NAME = 3
|
87
|
+
COLUMN_NAME = 9
|
88
|
+
end
|
89
|
+
|
90
|
+
module TableMetaData
|
91
|
+
TABLE_CAT = 1
|
92
|
+
TABLE_SCHEM = 2
|
93
|
+
TABLE_NAME = 3
|
94
|
+
TABLE_TYPE = 4
|
95
|
+
end
|
96
|
+
|
97
|
+
module PrimaryKeyMetaData
|
98
|
+
COLUMN_NAME = 4
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
# I want to use JDBC's DatabaseMetaData#getTypeInfo to choose the best native types to
|
104
|
+
# use for ActiveRecord's Adapter#native_database_types in a database-independent way,
|
105
|
+
# but apparently a database driver can return multiple types for a given
|
106
|
+
# java.sql.Types constant. So this type converter uses some heuristics to try to pick
|
107
|
+
# the best (most common) type to use. It's not great, it would be better to just
|
108
|
+
# delegate to each database's existin AR adapter's native_database_types method, but I
|
109
|
+
# wanted to try to do this in a way that didn't pull in all the other adapters as
|
110
|
+
# dependencies. Suggestions appreciated.
|
111
|
+
class JdbcTypeConverter
|
112
|
+
# The basic ActiveRecord types, mapped to an array of procs that are used to #select
|
113
|
+
# the best type. The procs are used as selectors in order until there is only one
|
114
|
+
# type left. If all the selectors are applied and there is still more than one
|
115
|
+
# type, an exception will be raised.
|
116
|
+
AR_TO_JDBC_TYPES = {
|
117
|
+
:string => [ lambda {|r| Jdbc::Types::VARCHAR == r['data_type'].to_i},
|
118
|
+
lambda {|r| r['type_name'] =~ /^varchar/i},
|
119
|
+
lambda {|r| r['type_name'] =~ /^varchar$/i},
|
120
|
+
lambda {|r| r['type_name'] =~ /varying/i}],
|
121
|
+
:text => [ lambda {|r| [Jdbc::Types::LONGVARCHAR, Jdbc::Types::CLOB].include?(r['data_type'].to_i)},
|
122
|
+
lambda {|r| r['type_name'] =~ /^(text|clob)$/i},
|
123
|
+
lambda {|r| r['type_name'] =~ /^character large object$/i},
|
124
|
+
lambda {|r| r['sql_data_type'] == 2005}],
|
125
|
+
:integer => [ lambda {|r| Jdbc::Types::INTEGER == r['data_type'].to_i},
|
126
|
+
lambda {|r| r['type_name'] =~ /^integer$/i},
|
127
|
+
lambda {|r| r['type_name'] =~ /^int4$/i},
|
128
|
+
lambda {|r| r['type_name'] =~ /^int$/i}],
|
129
|
+
:decimal => [ lambda {|r| Jdbc::Types::DECIMAL == r['data_type'].to_i},
|
130
|
+
lambda {|r| r['type_name'] =~ /^decimal$/i},
|
131
|
+
lambda {|r| r['type_name'] =~ /^numeric$/i},
|
132
|
+
lambda {|r| r['type_name'] =~ /^number$/i},
|
133
|
+
lambda {|r| r['precision'] == '38'},
|
134
|
+
lambda {|r| r['data_type'] == '2'}],
|
135
|
+
:float => [ lambda {|r| [Jdbc::Types::FLOAT,Jdbc::Types::DOUBLE, Jdbc::Types::REAL].include?(r['data_type'].to_i)},
|
136
|
+
lambda {|r| r['data_type'].to_i == Jdbc::Types::REAL}, #Prefer REAL to DOUBLE for Postgresql
|
137
|
+
lambda {|r| r['type_name'] =~ /^float/i},
|
138
|
+
lambda {|r| r['type_name'] =~ /^double$/i},
|
139
|
+
lambda {|r| r['type_name'] =~ /^real$/i},
|
140
|
+
lambda {|r| r['precision'] == '15'}],
|
141
|
+
:datetime => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
|
142
|
+
lambda {|r| r['type_name'] =~ /^datetime$/i},
|
143
|
+
lambda {|r| r['type_name'] =~ /^timestamp$/i},
|
144
|
+
lambda {|r| r['type_name'] =~ /^date/i}],
|
145
|
+
:timestamp => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
|
146
|
+
lambda {|r| r['type_name'] =~ /^timestamp$/i},
|
147
|
+
lambda {|r| r['type_name'] =~ /^datetime/i},
|
148
|
+
lambda {|r| r['type_name'] =~ /^date/i}],
|
149
|
+
:time => [ lambda {|r| Jdbc::Types::TIME == r['data_type'].to_i},
|
150
|
+
lambda {|r| r['type_name'] =~ /^time$/i},
|
151
|
+
lambda {|r| r['type_name'] =~ /^date/i}],
|
152
|
+
:date => [ lambda {|r| Jdbc::Types::DATE == r['data_type'].to_i},
|
153
|
+
lambda {|r| r['type_name'] =~ /^date$/i},
|
154
|
+
lambda {|r| r['type_name'] =~ /^date/i}],
|
155
|
+
:binary => [ lambda {|r| [Jdbc::Types::LONGVARBINARY,Jdbc::Types::BINARY,Jdbc::Types::BLOB].include?(r['data_type'].to_i)},
|
156
|
+
lambda {|r| r['type_name'] =~ /^blob/i},
|
157
|
+
lambda {|r| r['type_name'] =~ /sub_type 0$/i}, # For FireBird
|
158
|
+
lambda {|r| r['type_name'] =~ /^varbinary$/i}, # We want this sucker for Mimer
|
159
|
+
lambda {|r| r['type_name'] =~ /^binary$/i}, ],
|
160
|
+
:boolean => [ lambda {|r| [Jdbc::Types::TINYINT].include?(r['data_type'].to_i)},
|
161
|
+
lambda {|r| r['type_name'] =~ /^bool/i},
|
162
|
+
lambda {|r| r['data_type'] == '-7'},
|
163
|
+
lambda {|r| r['type_name'] =~ /^tinyint$/i},
|
164
|
+
lambda {|r| r['type_name'] =~ /^decimal$/i}]
|
165
|
+
}
|
166
|
+
|
167
|
+
def initialize(types)
|
168
|
+
@types = types
|
169
|
+
@types.each {|t| t['type_name'] ||= t['local_type_name']} # Sybase driver seems to want 'local_type_name'
|
170
|
+
end
|
171
|
+
|
172
|
+
def choose_best_types
|
173
|
+
type_map = {}
|
174
|
+
AR_TO_JDBC_TYPES.each_key do |k|
|
175
|
+
typerow = choose_type(k)
|
176
|
+
type_map[k] = { :name => typerow['type_name'].downcase }
|
177
|
+
case k
|
178
|
+
when :integer, :string, :decimal
|
179
|
+
type_map[k][:limit] = typerow['precision'] && typerow['precision'].to_i
|
180
|
+
when :boolean
|
181
|
+
type_map[k][:limit] = 1
|
182
|
+
end
|
183
|
+
end
|
184
|
+
type_map
|
185
|
+
end
|
186
|
+
|
187
|
+
def choose_type(ar_type)
|
188
|
+
procs = AR_TO_JDBC_TYPES[ar_type]
|
189
|
+
types = @types
|
190
|
+
procs.each do |p|
|
191
|
+
new_types = types.select(&p)
|
192
|
+
return new_types.first if new_types.length == 1
|
193
|
+
types = new_types if new_types.length > 0
|
194
|
+
end
|
195
|
+
raise "unable to choose type for #{ar_type} from:\n#{types.collect{|t| t['type_name']}.inspect}"
|
196
|
+
end
|
197
|
+
end
|
198
|
+
|
199
|
+
class JdbcDriver
|
200
|
+
def initialize(name)
|
201
|
+
@name = name
|
202
|
+
end
|
203
|
+
|
204
|
+
def driver_class
|
205
|
+
@driver_class ||= begin
|
206
|
+
driver_class_const = (@name[0...1].capitalize + @name[1..@name.length]).gsub(/\./, '_')
|
207
|
+
Jdbc::Mutex.synchronized do
|
208
|
+
unless Jdbc.const_defined?(driver_class_const)
|
209
|
+
driver_class_name = @name
|
210
|
+
Jdbc.module_eval do
|
211
|
+
include_class(driver_class_name) { driver_class_const }
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end
|
215
|
+
driver_class = Jdbc.const_get(driver_class_const)
|
216
|
+
raise "You specify a driver for your JDBC connection" unless driver_class
|
217
|
+
driver_class
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
def load
|
222
|
+
Jdbc::DriverManager.registerDriver(create)
|
223
|
+
end
|
224
|
+
|
225
|
+
def connection(url, user, pass)
|
226
|
+
Jdbc::DriverManager.getConnection(url, user, pass)
|
227
|
+
rescue
|
228
|
+
# bypass DriverManager to get around problem with dynamically loaded jdbc drivers
|
229
|
+
props = java.util.Properties.new
|
230
|
+
props.setProperty("user", user)
|
231
|
+
props.setProperty("password", pass)
|
232
|
+
create.connect(url, props)
|
233
|
+
end
|
234
|
+
|
235
|
+
def create
|
236
|
+
driver_class.new
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
class JdbcColumn < Column
|
241
|
+
attr_writer :limit, :precision
|
242
|
+
|
243
|
+
COLUMN_TYPES = ::JdbcSpec.constants.map{|c|
|
244
|
+
::JdbcSpec.const_get c }.select{ |c|
|
245
|
+
c.respond_to? :column_selector }.map{|c|
|
246
|
+
c.column_selector }.inject({}) { |h,val|
|
247
|
+
h[val[0]] = val[1]; h }
|
248
|
+
|
249
|
+
def initialize(config, name, default, *args)
|
250
|
+
ds = config[:driver].to_s
|
251
|
+
for reg, func in COLUMN_TYPES
|
252
|
+
if reg === ds
|
253
|
+
func.call(config,self)
|
254
|
+
end
|
255
|
+
end
|
256
|
+
super(name,default_value(default),*args)
|
257
|
+
init_column(name, default, *args)
|
258
|
+
end
|
259
|
+
|
260
|
+
def init_column(*args)
|
261
|
+
end
|
262
|
+
|
263
|
+
def default_value(val)
|
264
|
+
val
|
265
|
+
end
|
266
|
+
end
|
267
|
+
|
268
|
+
class JdbcConnection
|
269
|
+
attr_reader :adapter, :connection
|
270
|
+
|
271
|
+
def initialize(config)
|
272
|
+
@config = config.symbolize_keys!
|
273
|
+
if @config[:jndi]
|
274
|
+
begin
|
275
|
+
configure_jndi
|
276
|
+
rescue => e
|
277
|
+
warn "JNDI data source unavailable: #{e.message}; trying straight JDBC"
|
278
|
+
configure_jdbc
|
279
|
+
end
|
280
|
+
else
|
281
|
+
configure_jdbc
|
282
|
+
end
|
283
|
+
set_native_database_types
|
284
|
+
@stmts = {}
|
285
|
+
rescue Exception => e
|
286
|
+
raise "The driver encountered an error: #{e}"
|
287
|
+
end
|
288
|
+
|
289
|
+
def reconnect!
|
290
|
+
self.adapter.reconnect!
|
291
|
+
end
|
292
|
+
|
293
|
+
def adapter=(adapt)
|
294
|
+
@adapter = adapt
|
295
|
+
@tps = {}
|
296
|
+
@native_types.each_pair {|k,v| @tps[k] = v.inject({}) {|memo,kv| memo.merge({kv.first => (kv.last.dup rescue kv.last)})}}
|
297
|
+
adapt.modify_types(@tps)
|
298
|
+
end
|
299
|
+
|
300
|
+
# Default JDBC introspection for index metadata on the JdbcConnection.
|
301
|
+
# This is currently used for migrations by JdbcSpec::HSQDLB and JdbcSpec::Derby
|
302
|
+
# indexes with a little filtering tacked on.
|
303
|
+
#
|
304
|
+
# JDBC index metadata is denormalized (multiple rows may be returned for
|
305
|
+
# one index, one row per column in the index), so a simple block-based
|
306
|
+
# filter like that used for tables doesn't really work here. Callers
|
307
|
+
# should filter the return from this method instead.
|
308
|
+
#
|
309
|
+
# TODO: fix to use reconnect correctly
|
310
|
+
def indexes(table_name, name = nil, schema_name = nil)
|
311
|
+
metadata = @connection.getMetaData
|
312
|
+
unless String === table_name
|
313
|
+
table_name = table_name.to_s
|
314
|
+
else
|
315
|
+
table_name = table_name.dup
|
316
|
+
end
|
317
|
+
table_name.upcase! if metadata.storesUpperCaseIdentifiers
|
318
|
+
table_name.downcase! if metadata.storesLowerCaseIdentifiers
|
319
|
+
resultset = metadata.getIndexInfo(nil, schema_name, table_name, false, false)
|
320
|
+
primary_keys = primary_keys(table_name)
|
321
|
+
indexes = []
|
322
|
+
current_index = nil
|
323
|
+
while resultset.next
|
324
|
+
index_name = resultset.get_string(Jdbc::IndexMetaData::INDEX_NAME)
|
325
|
+
next unless index_name
|
326
|
+
index_name.downcase!
|
327
|
+
column_name = resultset.get_string(Jdbc::IndexMetaData::COLUMN_NAME).downcase
|
328
|
+
|
329
|
+
next if primary_keys.include? column_name
|
330
|
+
|
331
|
+
# We are working on a new index
|
332
|
+
if current_index != index_name
|
333
|
+
current_index = index_name
|
334
|
+
table_name = resultset.get_string(Jdbc::IndexMetaData::TABLE_NAME).downcase
|
335
|
+
non_unique = resultset.get_boolean(Jdbc::IndexMetaData::NON_UNIQUE)
|
336
|
+
|
337
|
+
# empty list for column names, we'll add to that in just a bit
|
338
|
+
indexes << IndexDefinition.new(table_name, index_name, !non_unique, [])
|
339
|
+
end
|
340
|
+
|
341
|
+
# One or more columns can be associated with an index
|
342
|
+
indexes.last.columns << column_name
|
343
|
+
end
|
344
|
+
resultset.close
|
345
|
+
indexes
|
346
|
+
rescue
|
347
|
+
if @connection.is_closed
|
348
|
+
reconnect!
|
349
|
+
retry
|
350
|
+
else
|
351
|
+
raise
|
352
|
+
end
|
353
|
+
ensure
|
354
|
+
metadata.close rescue nil
|
355
|
+
end
|
356
|
+
|
357
|
+
# def self.insert?(sql)
|
358
|
+
# /\A\s*insert/i =~ sql
|
359
|
+
# end
|
360
|
+
|
361
|
+
# def self.select?(sql)
|
362
|
+
# /\A\s*\(?\s*(select|show)/i =~ sql
|
363
|
+
# end
|
364
|
+
|
365
|
+
private
|
366
|
+
def configure_jndi
|
367
|
+
jndi = @config[:jndi].to_s
|
368
|
+
ctx = javax.naming.InitialContext.new
|
369
|
+
ds = ctx.lookup(jndi)
|
370
|
+
set_connection ds.connection
|
371
|
+
unless @config[:driver]
|
372
|
+
@config[:driver] = @connection.meta_data.connection.java_class.name
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
def configure_jdbc
|
377
|
+
driver = @config[:driver].to_s
|
378
|
+
user = @config[:username].to_s
|
379
|
+
pass = @config[:password].to_s
|
380
|
+
url = @config[:url].to_s
|
381
|
+
|
382
|
+
unless driver && url
|
383
|
+
raise ArgumentError, "jdbc adapter requires driver class and url"
|
384
|
+
end
|
385
|
+
|
386
|
+
if driver =~ /mysql/i
|
387
|
+
div = url =~ /\?/ ? '&' : '?'
|
388
|
+
url = "#{url}#{div}zeroDateTimeBehavior=convertToNull&jdbcCompliantTruncation=false&useUnicode=true&characterEncoding=utf8"
|
389
|
+
@config[:url] = url
|
390
|
+
end
|
391
|
+
|
392
|
+
jdbc_driver = JdbcDriver.new(driver)
|
393
|
+
jdbc_driver.load
|
394
|
+
connection = jdbc_driver.connection(url, user, pass)
|
395
|
+
set_connection connection
|
396
|
+
end
|
397
|
+
|
398
|
+
end
|
399
|
+
|
400
|
+
class JdbcAdapter < AbstractAdapter
|
401
|
+
attr_reader :config
|
402
|
+
|
403
|
+
ADAPTER_TYPES = ::JdbcSpec.constants.map{|c|
|
404
|
+
::JdbcSpec.const_get c }.select{ |c|
|
405
|
+
c.respond_to? :adapter_selector }.map{|c|
|
406
|
+
c.adapter_selector }.inject({}) { |h,val|
|
407
|
+
h[val[0]] = val[1]; h }
|
408
|
+
|
409
|
+
def initialize(connection, logger, config)
|
410
|
+
super(connection, logger)
|
411
|
+
@config = config
|
412
|
+
ds = config[:driver].to_s
|
413
|
+
for reg, func in ADAPTER_TYPES
|
414
|
+
if reg === ds
|
415
|
+
func.call(@config,self)
|
416
|
+
end
|
417
|
+
end
|
418
|
+
connection.adapter = self
|
419
|
+
end
|
420
|
+
|
421
|
+
def modify_types(tp)
|
422
|
+
tp
|
423
|
+
end
|
424
|
+
|
425
|
+
def adapter_name #:nodoc:
|
426
|
+
'JDBC'
|
427
|
+
end
|
428
|
+
|
429
|
+
def supports_migrations?
|
430
|
+
true
|
431
|
+
end
|
432
|
+
|
433
|
+
def native_database_types #:nodoc:
|
434
|
+
@connection.native_database_types
|
435
|
+
end
|
436
|
+
|
437
|
+
def database_name #:nodoc:
|
438
|
+
@connection.database_name
|
439
|
+
end
|
440
|
+
|
441
|
+
def native_sql_to_type(tp)
|
442
|
+
if /^(.*?)\(([0-9]+)\)/ =~ tp
|
443
|
+
tname = $1
|
444
|
+
limit = $2.to_i
|
445
|
+
ntype = native_database_types
|
446
|
+
if ntype[:primary_key] == tp
|
447
|
+
return :primary_key,nil
|
448
|
+
else
|
449
|
+
ntype.each do |name,val|
|
450
|
+
if name == :primary_key
|
451
|
+
next
|
452
|
+
end
|
453
|
+
if val[:name].downcase == tname.downcase && (val[:limit].nil? || val[:limit].to_i == limit)
|
454
|
+
return name,limit
|
455
|
+
end
|
456
|
+
end
|
457
|
+
end
|
458
|
+
elsif /^(.*?)/ =~ tp
|
459
|
+
tname = $1
|
460
|
+
ntype = native_database_types
|
461
|
+
if ntype[:primary_key] == tp
|
462
|
+
return :primary_key,nil
|
463
|
+
else
|
464
|
+
ntype.each do |name,val|
|
465
|
+
if val[:name].downcase == tname.downcase && val[:limit].nil?
|
466
|
+
return name,nil
|
467
|
+
end
|
468
|
+
end
|
469
|
+
end
|
470
|
+
else
|
471
|
+
return :string,255
|
472
|
+
end
|
473
|
+
return nil,nil
|
474
|
+
end
|
475
|
+
|
476
|
+
def reconnect!
|
477
|
+
@connection.close rescue nil
|
478
|
+
@connection = JdbcConnection.new(@config)
|
479
|
+
@connection.adapter = self
|
480
|
+
@connection
|
481
|
+
end
|
482
|
+
|
483
|
+
def select_all(sql, name = nil)
|
484
|
+
select(sql, name)
|
485
|
+
end
|
486
|
+
|
487
|
+
def select_one(sql, name = nil)
|
488
|
+
select(sql, name).first
|
489
|
+
end
|
490
|
+
|
491
|
+
def execute(sql, name = nil)
|
492
|
+
log_no_bench(sql, name) do
|
493
|
+
_execute(sql,name)
|
494
|
+
end
|
495
|
+
end
|
496
|
+
|
497
|
+
|
498
|
+
# we need to do it this way, to allow Rails stupid tests to always work
|
499
|
+
# even if we define a new execute method. Instead of mixing in a new
|
500
|
+
# execute, an _execute should be mixed in.
|
501
|
+
def _execute(sql, name = nil)
|
502
|
+
if JdbcConnection::select?(sql)
|
503
|
+
@connection.execute_query(sql)
|
504
|
+
elsif JdbcConnection::insert?(sql)
|
505
|
+
@connection.execute_insert(sql)
|
506
|
+
else
|
507
|
+
@connection.execute_update(sql)
|
508
|
+
end
|
509
|
+
end
|
510
|
+
|
511
|
+
def update(sql, name = nil) #:nodoc:
|
512
|
+
execute(sql, name)
|
513
|
+
end
|
514
|
+
|
515
|
+
def insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
516
|
+
id = execute(sql, name = nil)
|
517
|
+
id_value || id
|
518
|
+
end
|
519
|
+
|
520
|
+
def columns(table_name, name = nil)
|
521
|
+
@connection.columns(table_name.to_s)
|
522
|
+
end
|
523
|
+
|
524
|
+
def tables
|
525
|
+
@connection.tables
|
526
|
+
end
|
527
|
+
|
528
|
+
def indexes(table_name)
|
529
|
+
@connection.indexes(table_name)
|
530
|
+
end
|
531
|
+
|
532
|
+
def begin_db_transaction
|
533
|
+
@connection.begin
|
534
|
+
end
|
535
|
+
|
536
|
+
def commit_db_transaction
|
537
|
+
@connection.commit
|
538
|
+
end
|
539
|
+
|
540
|
+
def rollback_db_transaction
|
541
|
+
@connection.rollback
|
542
|
+
end
|
543
|
+
|
544
|
+
def write_large_object(*args)
|
545
|
+
@connection.write_large_object(*args)
|
546
|
+
end
|
547
|
+
|
548
|
+
private
|
549
|
+
def select(sql, name=nil)
|
550
|
+
execute(sql,name)
|
551
|
+
end
|
552
|
+
|
553
|
+
def log_no_bench(sql, name)
|
554
|
+
if block_given?
|
555
|
+
if @logger and @logger.level <= Logger::INFO
|
556
|
+
result = yield
|
557
|
+
log_info(sql, name, 0)
|
558
|
+
result
|
559
|
+
else
|
560
|
+
yield
|
561
|
+
end
|
562
|
+
else
|
563
|
+
log_info(sql, name, 0)
|
564
|
+
nil
|
565
|
+
end
|
566
|
+
rescue Exception => e
|
567
|
+
# Log message and raise exception.
|
568
|
+
message = "#{e.class.name}: #{e.message}: #{sql}"
|
569
|
+
|
570
|
+
log_info(message, name, 0)
|
571
|
+
raise ActiveRecord::StatementInvalid, message
|
572
|
+
end
|
573
|
+
end
|
574
|
+
end
|
575
|
+
end
|