activerecord-jdbc-adapter 0.6
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 +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
|