kb-activerecord-jdbc-adapter 0.9.7.1-java
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 +296 -0
- data/LICENSE.txt +21 -0
- data/Manifest.txt +139 -0
- data/README.txt +219 -0
- data/Rakefile +10 -0
- data/lib/active_record/connection_adapters/cachedb_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/derby_adapter.rb +13 -0
- data/lib/active_record/connection_adapters/h2_adapter.rb +13 -0
- data/lib/active_record/connection_adapters/hsqldb_adapter.rb +13 -0
- data/lib/active_record/connection_adapters/informix_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/jdbc_adapter.rb +661 -0
- data/lib/active_record/connection_adapters/jdbc_adapter_spec.rb +26 -0
- data/lib/active_record/connection_adapters/jndi_adapter.rb +1 -0
- data/lib/active_record/connection_adapters/mssql_adapter.rb +13 -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/active_record/connection_adapters/sqlite3_adapter.rb +13 -0
- data/lib/activerecord-jdbc-adapter.rb +6 -0
- data/lib/arel/engines/sql/compilers/db2_compiler.rb +9 -0
- data/lib/arel/engines/sql/compilers/derby_compiler.rb +6 -0
- data/lib/arel/engines/sql/compilers/h2_compiler.rb +6 -0
- data/lib/arel/engines/sql/compilers/hsqldb_compiler.rb +6 -0
- data/lib/arel/engines/sql/compilers/jdbc_compiler.rb +6 -0
- data/lib/generators/jdbc/jdbc_generator.rb +9 -0
- data/lib/jdbc_adapter.rb +27 -0
- data/lib/jdbc_adapter/jdbc.rake +122 -0
- data/lib/jdbc_adapter/jdbc_adapter_internal.jar +0 -0
- data/lib/jdbc_adapter/jdbc_cachedb.rb +33 -0
- data/lib/jdbc_adapter/jdbc_db2.rb +222 -0
- data/lib/jdbc_adapter/jdbc_derby.rb +426 -0
- data/lib/jdbc_adapter/jdbc_firebird.rb +109 -0
- data/lib/jdbc_adapter/jdbc_hsqldb.rb +221 -0
- data/lib/jdbc_adapter/jdbc_informix.rb +147 -0
- data/lib/jdbc_adapter/jdbc_mimer.rb +145 -0
- data/lib/jdbc_adapter/jdbc_mssql.rb +468 -0
- data/lib/jdbc_adapter/jdbc_mysql.rb +260 -0
- data/lib/jdbc_adapter/jdbc_oracle.rb +397 -0
- data/lib/jdbc_adapter/jdbc_postgre.rb +531 -0
- data/lib/jdbc_adapter/jdbc_sqlite3.rb +386 -0
- data/lib/jdbc_adapter/jdbc_sybase.rb +50 -0
- data/lib/jdbc_adapter/missing_functionality_helper.rb +87 -0
- data/lib/jdbc_adapter/railtie.rb +9 -0
- data/lib/jdbc_adapter/rake_tasks.rb +10 -0
- data/lib/jdbc_adapter/tsql_helper.rb +69 -0
- data/lib/jdbc_adapter/version.rb +5 -0
- data/lib/pg.rb +4 -0
- data/rails_generators/jdbc_generator.rb +15 -0
- data/rails_generators/templates/config/initializers/jdbc.rb +7 -0
- data/rails_generators/templates/lib/tasks/jdbc.rake +8 -0
- data/rakelib/compile.rake +23 -0
- data/rakelib/package.rake +91 -0
- data/rakelib/rails.rake +41 -0
- data/rakelib/test.rake +78 -0
- data/src/java/jdbc_adapter/JdbcAdapterInternalService.java +53 -0
- data/src/java/jdbc_adapter/JdbcConnectionFactory.java +36 -0
- data/src/java/jdbc_adapter/JdbcDerbySpec.java +293 -0
- data/src/java/jdbc_adapter/JdbcMySQLSpec.java +134 -0
- data/src/java/jdbc_adapter/MssqlRubyJdbcConnection.java +71 -0
- data/src/java/jdbc_adapter/PostgresRubyJdbcConnection.java +55 -0
- data/src/java/jdbc_adapter/RubyJdbcConnection.java +1176 -0
- data/src/java/jdbc_adapter/SQLBlock.java +27 -0
- data/src/java/jdbc_adapter/Sqlite3RubyJdbcConnection.java +41 -0
- data/test/abstract_db_create.rb +107 -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/cachedb_simple_test.rb +6 -0
- data/test/db/cachedb.rb +9 -0
- data/test/db/db2.rb +9 -0
- data/test/db/derby.rb +14 -0
- data/test/db/h2.rb +11 -0
- data/test/db/hsqldb.rb +12 -0
- data/test/db/informix.rb +11 -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/mssql.rb +9 -0
- data/test/db/mysql.rb +10 -0
- data/test/db/oracle.rb +34 -0
- data/test/db/postgres.rb +9 -0
- data/test/db/sqlite3.rb +15 -0
- data/test/db2_simple_test.rb +10 -0
- data/test/derby_migration_test.rb +21 -0
- data/test/derby_multibyte_test.rb +12 -0
- data/test/derby_simple_test.rb +21 -0
- data/test/generic_jdbc_connection_test.rb +9 -0
- data/test/h2_simple_test.rb +6 -0
- data/test/has_many_through.rb +79 -0
- data/test/helper.rb +5 -0
- data/test/hsqldb_simple_test.rb +6 -0
- data/test/informix_simple_test.rb +48 -0
- data/test/jdbc_adapter/jdbc_db2_test.rb +26 -0
- data/test/jdbc_adapter/jdbc_sybase_test.rb +33 -0
- data/test/jdbc_common.rb +25 -0
- data/test/jndi_callbacks_test.rb +38 -0
- data/test/jndi_test.rb +35 -0
- data/test/manualTestDatabase.rb +191 -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/add_not_null_column_to_table.rb +12 -0
- data/test/models/auto_id.rb +18 -0
- data/test/models/data_types.rb +28 -0
- data/test/models/entry.rb +23 -0
- data/test/models/mixed_case.rb +20 -0
- data/test/models/reserved_word.rb +18 -0
- data/test/models/string_id.rb +18 -0
- data/test/models/validates_uniqueness_of_string.rb +19 -0
- data/test/mssql_db_create_test.rb +26 -0
- data/test/mssql_identity_insert_test.rb +19 -0
- data/test/mssql_legacy_types_test.rb +58 -0
- data/test/mssql_limit_offset_test.rb +108 -0
- data/test/mssql_multibyte_test.rb +18 -0
- data/test/mssql_simple_test.rb +49 -0
- data/test/mysql_db_create_test.rb +25 -0
- data/test/mysql_info_test.rb +62 -0
- data/test/mysql_multibyte_test.rb +10 -0
- data/test/mysql_nonstandard_primary_key_test.rb +42 -0
- data/test/mysql_simple_test.rb +32 -0
- data/test/oracle_simple_test.rb +54 -0
- data/test/pick_rails_version.rb +3 -0
- data/test/postgres_db_create_test.rb +21 -0
- data/test/postgres_mixed_case_test.rb +19 -0
- data/test/postgres_nonseq_pkey_test.rb +40 -0
- data/test/postgres_reserved_test.rb +22 -0
- data/test/postgres_schema_search_path_test.rb +46 -0
- data/test/postgres_simple_test.rb +13 -0
- data/test/simple.rb +494 -0
- data/test/sqlite3_simple_test.rb +233 -0
- data/test/sybase_jtds_simple_test.rb +6 -0
- metadata +230 -0
data/README.txt
ADDED
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
activerecord-jdbc-adapter is a database adapter for Rails' ActiveRecord
|
|
2
|
+
component that can be used with JRuby[http://www.jruby.org/]. It allows use of
|
|
3
|
+
virtually any JDBC-compliant database with your JRuby on Rails application.
|
|
4
|
+
|
|
5
|
+
== Project Info
|
|
6
|
+
|
|
7
|
+
* Mailing Lists: http://kenai.com/projects/activerecord-jdbc/lists
|
|
8
|
+
* Issues: http://kenai.com/jira/browse/ACTIVERECORD_JDBC
|
|
9
|
+
* Source: git://kenai.com/activerecord-jdbc~main
|
|
10
|
+
git://github.com/nicksieger/activerecord-jdbc-adapter.git
|
|
11
|
+
|
|
12
|
+
== Databases
|
|
13
|
+
|
|
14
|
+
What's there, and what is not there:
|
|
15
|
+
|
|
16
|
+
* MySQL - Complete support
|
|
17
|
+
* PostgreSQL - Complete support
|
|
18
|
+
* Oracle - Complete support
|
|
19
|
+
* Microsoft SQL Server - Complete support
|
|
20
|
+
* DB2 - Complete, except for the migrations:
|
|
21
|
+
* change_column
|
|
22
|
+
* change_column_default
|
|
23
|
+
* remove_column
|
|
24
|
+
* rename_column
|
|
25
|
+
* add_index
|
|
26
|
+
* remove_index
|
|
27
|
+
* rename_table
|
|
28
|
+
* FireBird - Complete, except for change_column_default and rename_column
|
|
29
|
+
* Derby - Complete, except for:
|
|
30
|
+
* change_column
|
|
31
|
+
* change_column_default
|
|
32
|
+
* remove_column
|
|
33
|
+
* rename_column
|
|
34
|
+
* HSQLDB - Complete
|
|
35
|
+
* H2 - Complete
|
|
36
|
+
* SQLite3 - work in progress
|
|
37
|
+
* Informix - Fairly complete support, all tests pass and migrations appear to work. Comments welcome.
|
|
38
|
+
|
|
39
|
+
Other databases will require testing and likely a custom configuration module.
|
|
40
|
+
Please join the activerecord-jdbc
|
|
41
|
+
mailing-lists[http://kenai.com/projects/activerecord-jdbc/lists] to help us discover
|
|
42
|
+
support for more databases.
|
|
43
|
+
|
|
44
|
+
== Using ActiveRecord JDBC
|
|
45
|
+
|
|
46
|
+
=== Inside Rails
|
|
47
|
+
|
|
48
|
+
To use activerecord-jdbc-adapter with JRuby on Rails:
|
|
49
|
+
|
|
50
|
+
1. Choose the adapter you wish to gem install. The following pre-packaged
|
|
51
|
+
adapters are available:
|
|
52
|
+
|
|
53
|
+
* 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.
|
|
54
|
+
* mysql (<tt>activerecord-jdbcmysql-adapter</tt>)
|
|
55
|
+
* postgresql (<tt>activerecord-jdbcpostgresql-adapter</tt>)
|
|
56
|
+
* sqlite3 (<tt>activerecord-jdbcsqlite3-adapter</tt>)
|
|
57
|
+
* derby (<tt>activerecord-jdbcderby-adapter</tt>)
|
|
58
|
+
* hsqldb (<tt>activerecord-jdbchsqldb-adapter</tt>)
|
|
59
|
+
* h2 (<tt>activerecord-jdbch2-adapter</tt>)
|
|
60
|
+
* mssql (<tt>activerecord-jdbcmssql-adapter</tt>)
|
|
61
|
+
|
|
62
|
+
2a. For Rails 3, if you're generating a new application, use the
|
|
63
|
+
following command to generate your application:
|
|
64
|
+
|
|
65
|
+
jruby -S rails myapp -m http://jruby.org/rails3.rb
|
|
66
|
+
|
|
67
|
+
2b. Otherwise, you'll need to run the "jdbc" generator to prepare your
|
|
68
|
+
Rails application for JDBC.
|
|
69
|
+
|
|
70
|
+
If you're using Rails 3, first you'll need to modify your Gemfile
|
|
71
|
+
to use the activerecord-jdbc-adapter gem under JRuby. Change your
|
|
72
|
+
Gemfile to look like the following (using sqlite3 as an example):
|
|
73
|
+
|
|
74
|
+
if defined?(JRUBY_VERSION)
|
|
75
|
+
gem 'activerecord-jdbc-adapter', :require => false
|
|
76
|
+
gem 'jdbc-sqlite3, :require => false
|
|
77
|
+
else
|
|
78
|
+
gem sqlite3-ruby', :require => 'sqlite3'
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
Next, run the generator. With Rails 3:
|
|
82
|
+
|
|
83
|
+
jruby script/rails generate jdbc
|
|
84
|
+
|
|
85
|
+
With Rails 2:
|
|
86
|
+
|
|
87
|
+
jruby script/generate jdbc
|
|
88
|
+
|
|
89
|
+
The initializer and rake task files generated are guarded such that
|
|
90
|
+
they won't be loaded if you still run your application under C Ruby.
|
|
91
|
+
|
|
92
|
+
Legacy: If you're using Rails prior to version 2.0, you'll need to
|
|
93
|
+
add one-time setup to your config/environment.rb file in your Rails
|
|
94
|
+
application. Add the following lines just before the
|
|
95
|
+
<code>Rails::Initializer</code>. (If you're using
|
|
96
|
+
activerecord-jdbc-adapter under the old gem name used in versions
|
|
97
|
+
0.5 and earlier (ActiveRecord-JDBC), replace
|
|
98
|
+
'activerecord-jdbc-adapter' with 'ActiveRecord-JDBC' below.)
|
|
99
|
+
|
|
100
|
+
if RUBY_PLATFORM =~ /java/
|
|
101
|
+
require 'rubygems'
|
|
102
|
+
gem 'activerecord-jdbc-adapter'
|
|
103
|
+
require 'jdbc_adapter'
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
3. Configure your database.yml in the normal Rails style.
|
|
107
|
+
|
|
108
|
+
Legacy configuration: If you use one of the convenience
|
|
109
|
+
'activerecord-jdbcXXX-adapter' adapters, you can still put a 'jdbc'
|
|
110
|
+
prefix in front of the database adapter name as below.
|
|
111
|
+
|
|
112
|
+
development:
|
|
113
|
+
adapter: jdbcmysql
|
|
114
|
+
username: blog
|
|
115
|
+
password:
|
|
116
|
+
hostname: localhost
|
|
117
|
+
database: weblog_development
|
|
118
|
+
|
|
119
|
+
For other databases, you'll need to know the database driver class
|
|
120
|
+
and URL. Example:
|
|
121
|
+
|
|
122
|
+
development:
|
|
123
|
+
adapter: jdbc
|
|
124
|
+
username: blog
|
|
125
|
+
password:
|
|
126
|
+
driver: com.mysql.jdbc.Driver
|
|
127
|
+
url: jdbc:mysql://localhost:3306/weblog_development
|
|
128
|
+
|
|
129
|
+
For JNDI data sources, you may simply specify the database type
|
|
130
|
+
using the adapter key and the JNDI location as follows:
|
|
131
|
+
|
|
132
|
+
production:
|
|
133
|
+
adapter: mysql
|
|
134
|
+
jndi: jdbc/mysqldb
|
|
135
|
+
|
|
136
|
+
=== Standalone, with ActiveRecord
|
|
137
|
+
|
|
138
|
+
1. Install the gem with JRuby:
|
|
139
|
+
|
|
140
|
+
jruby -S gem install activerecord-jdbc-adapter
|
|
141
|
+
|
|
142
|
+
If you wish to use the adapter for a specific database, you can install it
|
|
143
|
+
directly and a driver gem will be installed as well:
|
|
144
|
+
|
|
145
|
+
jruby -S gem install activerecord-jdbcderby-adapter
|
|
146
|
+
|
|
147
|
+
2. If using ActiveRecord 2.0 (Rails 2.0) or greater, you can skip to the next
|
|
148
|
+
step. Otherwise, ensure the following code gets executed in your script:
|
|
149
|
+
|
|
150
|
+
require 'rubygems'
|
|
151
|
+
gem 'activerecord-jdbc-adapter'
|
|
152
|
+
require 'jdbc_adapter'
|
|
153
|
+
require 'active_record'
|
|
154
|
+
|
|
155
|
+
3. After this you can establish a JDBC connection like this:
|
|
156
|
+
|
|
157
|
+
ActiveRecord::Base.establish_connection(
|
|
158
|
+
:adapter => 'jdbcderby',
|
|
159
|
+
:database => "db/my-database"
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
or like this (but requires that you manually put the driver jar on the classpath):
|
|
163
|
+
|
|
164
|
+
ActiveRecord::Base.establish_connection(
|
|
165
|
+
:adapter => 'jdbc',
|
|
166
|
+
:driver => 'org.apache.derby.jdbc.EmbeddedDriver',
|
|
167
|
+
:url => 'jdbc:derby:test_ar;create=true'
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
== Getting the source
|
|
171
|
+
|
|
172
|
+
The source for activerecord-jdbc-adapter is available using git.
|
|
173
|
+
|
|
174
|
+
git clone git://github.com/nicksieger/activerecord-jdbc-adapter.git
|
|
175
|
+
|
|
176
|
+
== Feedback
|
|
177
|
+
|
|
178
|
+
Please file bug reports at
|
|
179
|
+
http://kenai.com/jira/browse/ACTIVERECORD_JDBC. If you're not sure if
|
|
180
|
+
something's a bug, feel free to pre-report it on the mailing lists.
|
|
181
|
+
|
|
182
|
+
== Running AR-JDBC's Tests
|
|
183
|
+
|
|
184
|
+
Drivers for 6 open-source databases are included. Provided you have MySQL
|
|
185
|
+
installed, you can simply type <tt>jruby -S rake</tt> to run the tests. A
|
|
186
|
+
database named <tt>weblog_development</tt> is needed beforehand with a
|
|
187
|
+
connection user of "blog" and an empty password.
|
|
188
|
+
|
|
189
|
+
If you also have PostgreSQL available, those tests will be run if the
|
|
190
|
+
`psql' executable can be found. Also ensure you have a database named
|
|
191
|
+
<tt>weblog_development</tt> and a user named "blog" and an empty
|
|
192
|
+
password.
|
|
193
|
+
|
|
194
|
+
If you want rails logging enabled during these test runs you can edit
|
|
195
|
+
test/jdbc_common.rb and add the following line:
|
|
196
|
+
|
|
197
|
+
require 'db/logger'
|
|
198
|
+
|
|
199
|
+
== Running AR Tests
|
|
200
|
+
|
|
201
|
+
To run the current AR-JDBC sources with ActiveRecord, just use the
|
|
202
|
+
included "rails:test" task. Be sure to specify a driver and a path to
|
|
203
|
+
the ActiveRecord sources.
|
|
204
|
+
|
|
205
|
+
jruby -S rake rails:test DRIVER=mysql RAILS=/path/activerecord_source_dir
|
|
206
|
+
|
|
207
|
+
== Authors
|
|
208
|
+
|
|
209
|
+
This project was written by Nick Sieger <nick@nicksieger.com> and Ola Bini
|
|
210
|
+
<olabini@gmail.com> with lots of help from the JRuby community.
|
|
211
|
+
|
|
212
|
+
== License
|
|
213
|
+
|
|
214
|
+
activerecord-jdbc-adapter is released under a BSD license. See the LICENSE file
|
|
215
|
+
included with the distribution for details.
|
|
216
|
+
|
|
217
|
+
Open-source driver gems for activerecord-jdbc-adapter are licensed under the
|
|
218
|
+
same license the database's drivers are licensed. See each driver gem's
|
|
219
|
+
LICENSE.txt file for details.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
require 'rake/testtask'
|
|
2
|
+
require 'rake/clean'
|
|
3
|
+
CLEAN.include 'derby*', 'test.db.*','test/reports', 'test.sqlite3','lib/**/*.jar','manifest.mf', '*.log'
|
|
4
|
+
|
|
5
|
+
task :default => [:java_compile, :test]
|
|
6
|
+
|
|
7
|
+
task :filelist do
|
|
8
|
+
puts FileList['pkg/**/*'].inspect
|
|
9
|
+
end
|
|
10
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
require 'active_record/connection_adapters/jdbc_adapter'
|
|
@@ -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,13 @@
|
|
|
1
|
+
tried_gem = false
|
|
2
|
+
begin
|
|
3
|
+
require "jdbc/h2"
|
|
4
|
+
rescue LoadError
|
|
5
|
+
unless tried_gem
|
|
6
|
+
require 'rubygems'
|
|
7
|
+
gem "jdbc-h2"
|
|
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,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 @@
|
|
|
1
|
+
require 'active_record/connection_adapters/jdbc_adapter'
|
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
require 'active_record/version'
|
|
2
|
+
require 'active_record/connection_adapters/abstract_adapter'
|
|
3
|
+
require 'java'
|
|
4
|
+
require 'active_record/connection_adapters/jdbc_adapter_spec'
|
|
5
|
+
require 'jdbc_adapter/jdbc_adapter_internal'
|
|
6
|
+
require 'bigdecimal'
|
|
7
|
+
|
|
8
|
+
# AR's 2.2 version of this method is sufficient, but we need it for
|
|
9
|
+
# older versions
|
|
10
|
+
if ActiveRecord::VERSION::MAJOR <= 2 && ActiveRecord::VERSION::MINOR < 2
|
|
11
|
+
module ActiveRecord
|
|
12
|
+
module ConnectionAdapters # :nodoc:
|
|
13
|
+
module SchemaStatements
|
|
14
|
+
# Convert the speficied column type to a SQL string.
|
|
15
|
+
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
|
16
|
+
if native = native_database_types[type]
|
|
17
|
+
column_type_sql = (native.is_a?(Hash) ? native[:name] : native).dup
|
|
18
|
+
|
|
19
|
+
if type == :decimal # ignore limit, use precision and scale
|
|
20
|
+
scale ||= native[:scale]
|
|
21
|
+
|
|
22
|
+
if precision ||= native[:precision]
|
|
23
|
+
if scale
|
|
24
|
+
column_type_sql << "(#{precision},#{scale})"
|
|
25
|
+
else
|
|
26
|
+
column_type_sql << "(#{precision})"
|
|
27
|
+
end
|
|
28
|
+
elsif scale
|
|
29
|
+
raise ArgumentError, "Error adding decimal column: precision cannot be empty if scale if specified"
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
elsif limit ||= native.is_a?(Hash) && native[:limit]
|
|
33
|
+
column_type_sql << "(#{limit})"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
column_type_sql
|
|
37
|
+
else
|
|
38
|
+
type
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
module JdbcSpec
|
|
47
|
+
module ActiveRecordExtensions
|
|
48
|
+
def jdbc_connection(config)
|
|
49
|
+
::ActiveRecord::ConnectionAdapters::JdbcAdapter.new(nil, logger, config)
|
|
50
|
+
end
|
|
51
|
+
alias jndi_connection jdbc_connection
|
|
52
|
+
|
|
53
|
+
def embedded_driver(config)
|
|
54
|
+
config[:username] ||= "sa"
|
|
55
|
+
config[:password] ||= ""
|
|
56
|
+
jdbc_connection(config)
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
module QuotedPrimaryKeyExtension
|
|
61
|
+
def self.extended(base)
|
|
62
|
+
# Rails 3 method Rails 2 method
|
|
63
|
+
meth = [:arel_attributes_values, :attributes_with_quotes].detect do |m|
|
|
64
|
+
base.private_instance_methods.include?(m.to_s)
|
|
65
|
+
end
|
|
66
|
+
pk_hash_key = "self.class.primary_key"
|
|
67
|
+
pk_hash_value = '"?"'
|
|
68
|
+
if meth == :arel_attributes_values
|
|
69
|
+
pk_hash_key = "self.class.arel_table[#{pk_hash_key}]"
|
|
70
|
+
pk_hash_value = "Arel::SqlLiteral.new(#{pk_hash_value})"
|
|
71
|
+
end
|
|
72
|
+
if meth
|
|
73
|
+
base.module_eval %{
|
|
74
|
+
alias :#{meth}_pre_pk :#{meth}
|
|
75
|
+
def #{meth}(include_primary_key = true, *args) #:nodoc:
|
|
76
|
+
aq = #{meth}_pre_pk(include_primary_key, *args)
|
|
77
|
+
if connection.is_a?(JdbcSpec::Oracle) || connection.is_a?(JdbcSpec::Mimer)
|
|
78
|
+
aq[#{pk_hash_key}] = #{pk_hash_value} if include_primary_key && aq[#{pk_hash_key}].nil?
|
|
79
|
+
end
|
|
80
|
+
aq
|
|
81
|
+
end
|
|
82
|
+
}
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
module ActiveRecord
|
|
89
|
+
class Base
|
|
90
|
+
extend JdbcSpec::ActiveRecordExtensions
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
module ConnectionAdapters
|
|
94
|
+
module Java
|
|
95
|
+
Class = java.lang.Class
|
|
96
|
+
URL = java.net.URL
|
|
97
|
+
URLClassLoader = java.net.URLClassLoader
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
module Jdbc
|
|
101
|
+
Mutex = java.lang.Object.new
|
|
102
|
+
DriverManager = java.sql.DriverManager
|
|
103
|
+
Statement = java.sql.Statement
|
|
104
|
+
Types = java.sql.Types
|
|
105
|
+
|
|
106
|
+
# some symbolic constants for the benefit of the JDBC-based
|
|
107
|
+
# JdbcConnection#indexes method
|
|
108
|
+
module IndexMetaData
|
|
109
|
+
INDEX_NAME = 6
|
|
110
|
+
NON_UNIQUE = 4
|
|
111
|
+
TABLE_NAME = 3
|
|
112
|
+
COLUMN_NAME = 9
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
module TableMetaData
|
|
116
|
+
TABLE_CAT = 1
|
|
117
|
+
TABLE_SCHEM = 2
|
|
118
|
+
TABLE_NAME = 3
|
|
119
|
+
TABLE_TYPE = 4
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
module PrimaryKeyMetaData
|
|
123
|
+
COLUMN_NAME = 4
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
# I want to use JDBC's DatabaseMetaData#getTypeInfo to choose the best native types to
|
|
129
|
+
# use for ActiveRecord's Adapter#native_database_types in a database-independent way,
|
|
130
|
+
# but apparently a database driver can return multiple types for a given
|
|
131
|
+
# java.sql.Types constant. So this type converter uses some heuristics to try to pick
|
|
132
|
+
# the best (most common) type to use. It's not great, it would be better to just
|
|
133
|
+
# delegate to each database's existin AR adapter's native_database_types method, but I
|
|
134
|
+
# wanted to try to do this in a way that didn't pull in all the other adapters as
|
|
135
|
+
# dependencies. Suggestions appreciated.
|
|
136
|
+
class JdbcTypeConverter
|
|
137
|
+
# The basic ActiveRecord types, mapped to an array of procs that are used to #select
|
|
138
|
+
# the best type. The procs are used as selectors in order until there is only one
|
|
139
|
+
# type left. If all the selectors are applied and there is still more than one
|
|
140
|
+
# type, an exception will be raised.
|
|
141
|
+
AR_TO_JDBC_TYPES = {
|
|
142
|
+
:string => [ lambda {|r| Jdbc::Types::VARCHAR == r['data_type'].to_i},
|
|
143
|
+
lambda {|r| r['type_name'] =~ /^varchar/i},
|
|
144
|
+
lambda {|r| r['type_name'] =~ /^varchar$/i},
|
|
145
|
+
lambda {|r| r['type_name'] =~ /varying/i}],
|
|
146
|
+
:text => [ lambda {|r| [Jdbc::Types::LONGVARCHAR, Jdbc::Types::CLOB].include?(r['data_type'].to_i)},
|
|
147
|
+
lambda {|r| r['type_name'] =~ /^text$/i}, # For Informix
|
|
148
|
+
lambda {|r| r['type_name'] =~ /^(text|clob)$/i},
|
|
149
|
+
lambda {|r| r['type_name'] =~ /^character large object$/i},
|
|
150
|
+
lambda {|r| r['sql_data_type'] == 2005}],
|
|
151
|
+
:integer => [ lambda {|r| Jdbc::Types::INTEGER == r['data_type'].to_i},
|
|
152
|
+
lambda {|r| r['type_name'] =~ /^integer$/i},
|
|
153
|
+
lambda {|r| r['type_name'] =~ /^int4$/i},
|
|
154
|
+
lambda {|r| r['type_name'] =~ /^int$/i}],
|
|
155
|
+
:decimal => [ lambda {|r| Jdbc::Types::DECIMAL == r['data_type'].to_i},
|
|
156
|
+
lambda {|r| r['type_name'] =~ /^decimal$/i},
|
|
157
|
+
lambda {|r| r['type_name'] =~ /^numeric$/i},
|
|
158
|
+
lambda {|r| r['type_name'] =~ /^number$/i},
|
|
159
|
+
lambda {|r| r['type_name'] =~ /^real$/i},
|
|
160
|
+
lambda {|r| r['precision'] == '38'},
|
|
161
|
+
lambda {|r| r['data_type'] == '2'}],
|
|
162
|
+
:float => [ lambda {|r| [Jdbc::Types::FLOAT,Jdbc::Types::DOUBLE, Jdbc::Types::REAL].include?(r['data_type'].to_i)},
|
|
163
|
+
lambda {|r| r['data_type'].to_i == Jdbc::Types::REAL}, #Prefer REAL to DOUBLE for Postgresql
|
|
164
|
+
lambda {|r| r['type_name'] =~ /^float/i},
|
|
165
|
+
lambda {|r| r['type_name'] =~ /^double$/i},
|
|
166
|
+
lambda {|r| r['type_name'] =~ /^real$/i},
|
|
167
|
+
lambda {|r| r['precision'] == '15'}],
|
|
168
|
+
:datetime => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
|
|
169
|
+
lambda {|r| r['type_name'] =~ /^datetime$/i},
|
|
170
|
+
lambda {|r| r['type_name'] =~ /^timestamp$/i},
|
|
171
|
+
lambda {|r| r['type_name'] =~ /^date/i},
|
|
172
|
+
lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
|
|
173
|
+
:timestamp => [ lambda {|r| Jdbc::Types::TIMESTAMP == r['data_type'].to_i},
|
|
174
|
+
lambda {|r| r['type_name'] =~ /^timestamp$/i},
|
|
175
|
+
lambda {|r| r['type_name'] =~ /^datetime/i},
|
|
176
|
+
lambda {|r| r['type_name'] =~ /^date/i},
|
|
177
|
+
lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
|
|
178
|
+
:time => [ lambda {|r| Jdbc::Types::TIME == r['data_type'].to_i},
|
|
179
|
+
lambda {|r| r['type_name'] =~ /^time$/i},
|
|
180
|
+
lambda {|r| r['type_name'] =~ /^datetime/i}, # For Informix
|
|
181
|
+
lambda {|r| r['type_name'] =~ /^date/i},
|
|
182
|
+
lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver
|
|
183
|
+
:date => [ lambda {|r| Jdbc::Types::DATE == r['data_type'].to_i},
|
|
184
|
+
lambda {|r| r['type_name'] =~ /^date$/i},
|
|
185
|
+
lambda {|r| r['type_name'] =~ /^date/i},
|
|
186
|
+
lambda {|r| r['type_name'] =~ /^integer/i}], #Num of milliseconds for SQLite3 JDBC Driver3
|
|
187
|
+
:binary => [ lambda {|r| [Jdbc::Types::LONGVARBINARY,Jdbc::Types::BINARY,Jdbc::Types::BLOB].include?(r['data_type'].to_i)},
|
|
188
|
+
lambda {|r| r['type_name'] =~ /^blob/i},
|
|
189
|
+
lambda {|r| r['type_name'] =~ /sub_type 0$/i}, # For FireBird
|
|
190
|
+
lambda {|r| r['type_name'] =~ /^varbinary$/i}, # We want this sucker for Mimer
|
|
191
|
+
lambda {|r| r['type_name'] =~ /^binary$/i}, ],
|
|
192
|
+
:boolean => [ lambda {|r| [Jdbc::Types::TINYINT].include?(r['data_type'].to_i)},
|
|
193
|
+
lambda {|r| r['type_name'] =~ /^bool/i},
|
|
194
|
+
lambda {|r| r['data_type'] == '-7'},
|
|
195
|
+
lambda {|r| r['type_name'] =~ /^tinyint$/i},
|
|
196
|
+
lambda {|r| r['type_name'] =~ /^decimal$/i},
|
|
197
|
+
lambda {|r| r['type_name'] =~ /^integer$/i}]
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
def initialize(types)
|
|
201
|
+
@types = types
|
|
202
|
+
@types.each {|t| t['type_name'] ||= t['local_type_name']} # Sybase driver seems to want 'local_type_name'
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
def choose_best_types
|
|
206
|
+
type_map = {}
|
|
207
|
+
@types.each do |row|
|
|
208
|
+
name = row['type_name'].downcase
|
|
209
|
+
k = name.to_sym
|
|
210
|
+
type_map[k] = { :name => name }
|
|
211
|
+
type_map[k][:limit] = row['precision'].to_i if row['precision']
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
AR_TO_JDBC_TYPES.keys.each do |k|
|
|
215
|
+
typerow = choose_type(k)
|
|
216
|
+
type_map[k] = { :name => typerow['type_name'].downcase }
|
|
217
|
+
case k
|
|
218
|
+
when :integer, :string, :decimal
|
|
219
|
+
type_map[k][:limit] = typerow['precision'] && typerow['precision'].to_i
|
|
220
|
+
when :boolean
|
|
221
|
+
type_map[k][:limit] = 1
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
type_map
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def choose_type(ar_type)
|
|
228
|
+
procs = AR_TO_JDBC_TYPES[ar_type]
|
|
229
|
+
types = @types
|
|
230
|
+
procs.each do |p|
|
|
231
|
+
new_types = types.reject {|r| r["data_type"].to_i == Jdbc::Types::OTHER}
|
|
232
|
+
new_types = new_types.select(&p)
|
|
233
|
+
new_types = new_types.inject([]) do |typs,t|
|
|
234
|
+
typs << t unless typs.detect {|el| el['type_name'] == t['type_name']}
|
|
235
|
+
typs
|
|
236
|
+
end
|
|
237
|
+
return new_types.first if new_types.length == 1
|
|
238
|
+
types = new_types if new_types.length > 0
|
|
239
|
+
end
|
|
240
|
+
raise "unable to choose type for #{ar_type} from:\n#{types.collect{|t| t['type_name']}.inspect}"
|
|
241
|
+
end
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
class JdbcDriver
|
|
245
|
+
def initialize(name)
|
|
246
|
+
@name = name
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
def driver_class
|
|
250
|
+
@driver_class ||= begin
|
|
251
|
+
driver_class_const = (@name[0...1].capitalize + @name[1..@name.length]).gsub(/\./, '_')
|
|
252
|
+
Jdbc::Mutex.synchronized do
|
|
253
|
+
unless Jdbc.const_defined?(driver_class_const)
|
|
254
|
+
driver_class_name = @name
|
|
255
|
+
Jdbc.module_eval do
|
|
256
|
+
include_class(driver_class_name) { driver_class_const }
|
|
257
|
+
end
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
driver_class = Jdbc.const_get(driver_class_const)
|
|
261
|
+
raise "You specify a driver for your JDBC connection" unless driver_class
|
|
262
|
+
driver_class
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def load
|
|
267
|
+
Jdbc::DriverManager.registerDriver(create)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def connection(url, user, pass)
|
|
271
|
+
Jdbc::DriverManager.getConnection(url, user, pass)
|
|
272
|
+
rescue
|
|
273
|
+
# bypass DriverManager to get around problem with dynamically loaded jdbc drivers
|
|
274
|
+
props = java.util.Properties.new
|
|
275
|
+
props.setProperty("user", user)
|
|
276
|
+
props.setProperty("password", pass)
|
|
277
|
+
create.connect(url, props)
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
def create
|
|
281
|
+
driver_class.new
|
|
282
|
+
end
|
|
283
|
+
end
|
|
284
|
+
|
|
285
|
+
class JdbcColumn < Column
|
|
286
|
+
attr_writer :limit, :precision
|
|
287
|
+
|
|
288
|
+
COLUMN_TYPES = ::JdbcSpec.constants.map{|c|
|
|
289
|
+
::JdbcSpec.const_get c }.select{ |c|
|
|
290
|
+
c.respond_to? :column_selector }.map{|c|
|
|
291
|
+
c.column_selector }.inject({}) { |h,val|
|
|
292
|
+
h[val[0]] = val[1]; h }
|
|
293
|
+
|
|
294
|
+
def initialize(config, name, default, *args)
|
|
295
|
+
dialect = config[:dialect] || config[:driver]
|
|
296
|
+
for reg, func in COLUMN_TYPES
|
|
297
|
+
if reg === dialect.to_s
|
|
298
|
+
func.call(config,self)
|
|
299
|
+
end
|
|
300
|
+
end
|
|
301
|
+
super(name,default_value(default),*args)
|
|
302
|
+
init_column(name, default, *args)
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
def init_column(*args)
|
|
306
|
+
end
|
|
307
|
+
|
|
308
|
+
def default_value(val)
|
|
309
|
+
val
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
include_class "jdbc_adapter.JdbcConnectionFactory"
|
|
314
|
+
|
|
315
|
+
class JdbcConnection
|
|
316
|
+
attr_reader :adapter, :connection_factory
|
|
317
|
+
|
|
318
|
+
# @native_database_types - setup properly by adapter= versus set_native_database_types.
|
|
319
|
+
# This contains type information for the adapter. Individual adapters can make tweaks
|
|
320
|
+
# by defined modify_types
|
|
321
|
+
#
|
|
322
|
+
# @native_types - This is the default type settings sans any modifications by the
|
|
323
|
+
# individual adapter. My guess is that if we loaded two adapters of different types
|
|
324
|
+
# then this is used as a base to be tweaked by each adapter to create @native_database_types
|
|
325
|
+
|
|
326
|
+
def initialize(config)
|
|
327
|
+
@config = config.symbolize_keys!
|
|
328
|
+
@config[:retry_count] ||= 5
|
|
329
|
+
@config[:connection_alive_sql] ||= "select 1"
|
|
330
|
+
if @config[:jndi]
|
|
331
|
+
begin
|
|
332
|
+
configure_jndi
|
|
333
|
+
rescue => e
|
|
334
|
+
warn "JNDI data source unavailable: #{e.message}; trying straight JDBC"
|
|
335
|
+
configure_jdbc
|
|
336
|
+
end
|
|
337
|
+
else
|
|
338
|
+
configure_jdbc
|
|
339
|
+
end
|
|
340
|
+
connection # force the connection to load
|
|
341
|
+
set_native_database_types
|
|
342
|
+
@stmts = {}
|
|
343
|
+
rescue Exception => e
|
|
344
|
+
raise "The driver encountered an error: #{e}"
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
def adapter=(adapter)
|
|
348
|
+
@adapter = adapter
|
|
349
|
+
@native_database_types = dup_native_types
|
|
350
|
+
@adapter.modify_types(@native_database_types)
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
# Duplicate all native types into new hash structure so it can be modified
|
|
354
|
+
# without destroying original structure.
|
|
355
|
+
def dup_native_types
|
|
356
|
+
types = {}
|
|
357
|
+
@native_types.each_pair do |k, v|
|
|
358
|
+
types[k] = v.inject({}) do |memo, kv|
|
|
359
|
+
memo[kv.first] = begin kv.last.dup rescue kv.last end
|
|
360
|
+
memo
|
|
361
|
+
end
|
|
362
|
+
end
|
|
363
|
+
types
|
|
364
|
+
end
|
|
365
|
+
private :dup_native_types
|
|
366
|
+
|
|
367
|
+
def jndi_connection?
|
|
368
|
+
@jndi_connection
|
|
369
|
+
end
|
|
370
|
+
|
|
371
|
+
private
|
|
372
|
+
def configure_jndi
|
|
373
|
+
jndi = @config[:jndi].to_s
|
|
374
|
+
ctx = javax.naming.InitialContext.new
|
|
375
|
+
ds = ctx.lookup(jndi)
|
|
376
|
+
@connection_factory = JdbcConnectionFactory.impl do
|
|
377
|
+
ds.connection
|
|
378
|
+
end
|
|
379
|
+
unless @config[:driver]
|
|
380
|
+
@config[:driver] = connection.meta_data.connection.java_class.name
|
|
381
|
+
end
|
|
382
|
+
@jndi_connection = true
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def configure_jdbc
|
|
386
|
+
driver = @config[:driver].to_s
|
|
387
|
+
user = @config[:username].to_s
|
|
388
|
+
pass = @config[:password].to_s
|
|
389
|
+
url = @config[:url].to_s
|
|
390
|
+
|
|
391
|
+
unless driver && url
|
|
392
|
+
raise ::ActiveRecord::ConnectionFailed, "jdbc adapter requires driver class and url"
|
|
393
|
+
end
|
|
394
|
+
|
|
395
|
+
jdbc_driver = JdbcDriver.new(driver)
|
|
396
|
+
jdbc_driver.load
|
|
397
|
+
@connection_factory = JdbcConnectionFactory.impl do
|
|
398
|
+
jdbc_driver.connection(url, user, pass)
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
class JdbcAdapter < AbstractAdapter
|
|
404
|
+
module ShadowCoreMethods
|
|
405
|
+
def alias_chained_method(meth, feature, target)
|
|
406
|
+
if instance_methods.include?("#{meth}_without_#{feature}")
|
|
407
|
+
alias_method "#{meth}_without_#{feature}".to_sym, target
|
|
408
|
+
else
|
|
409
|
+
alias_method meth, target if meth != target
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
end
|
|
413
|
+
|
|
414
|
+
module CompatibilityMethods
|
|
415
|
+
def self.needed?(base)
|
|
416
|
+
!base.instance_methods.include?("quote_table_name")
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def quote_table_name(name)
|
|
420
|
+
quote_column_name(name)
|
|
421
|
+
end
|
|
422
|
+
end
|
|
423
|
+
|
|
424
|
+
module ConnectionPoolCallbacks
|
|
425
|
+
def self.included(base)
|
|
426
|
+
if base.respond_to?(:set_callback) # Rails 3 callbacks
|
|
427
|
+
base.set_callback :checkin, :after, :on_checkin
|
|
428
|
+
base.set_callback :checkout, :before, :on_checkout
|
|
429
|
+
else
|
|
430
|
+
base.checkin :on_checkin
|
|
431
|
+
base.checkout :on_checkout
|
|
432
|
+
end
|
|
433
|
+
end
|
|
434
|
+
|
|
435
|
+
def self.needed?
|
|
436
|
+
ActiveRecord::Base.respond_to?(:connection_pool)
|
|
437
|
+
end
|
|
438
|
+
|
|
439
|
+
def on_checkin
|
|
440
|
+
# default implementation does nothing
|
|
441
|
+
end
|
|
442
|
+
|
|
443
|
+
def on_checkout
|
|
444
|
+
# default implementation does nothing
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
module JndiConnectionPoolCallbacks
|
|
449
|
+
def self.prepare(adapter, conn)
|
|
450
|
+
if ActiveRecord::Base.respond_to?(:connection_pool) && conn.jndi_connection?
|
|
451
|
+
adapter.extend self
|
|
452
|
+
conn.disconnect! # disconnect initial connection in JdbcConnection#initialize
|
|
453
|
+
end
|
|
454
|
+
end
|
|
455
|
+
|
|
456
|
+
def on_checkin
|
|
457
|
+
disconnect!
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
def on_checkout
|
|
461
|
+
reconnect!
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
extend ShadowCoreMethods
|
|
466
|
+
include CompatibilityMethods if CompatibilityMethods.needed?(self)
|
|
467
|
+
include ConnectionPoolCallbacks if ConnectionPoolCallbacks.needed?
|
|
468
|
+
|
|
469
|
+
attr_reader :config
|
|
470
|
+
|
|
471
|
+
def initialize(connection, logger, config)
|
|
472
|
+
@config = config
|
|
473
|
+
spec = adapter_spec config
|
|
474
|
+
unless connection
|
|
475
|
+
connection_class = jdbc_connection_class spec
|
|
476
|
+
connection = connection_class.new config
|
|
477
|
+
end
|
|
478
|
+
super(connection, logger)
|
|
479
|
+
extend spec if spec
|
|
480
|
+
connection.adapter = self
|
|
481
|
+
JndiConnectionPoolCallbacks.prepare(self, connection)
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
def jdbc_connection_class(spec)
|
|
485
|
+
connection_class = spec.jdbc_connection_class if spec && spec.respond_to?(:jdbc_connection_class)
|
|
486
|
+
connection_class = ::ActiveRecord::ConnectionAdapters::JdbcConnection unless connection_class
|
|
487
|
+
connection_class
|
|
488
|
+
end
|
|
489
|
+
|
|
490
|
+
# Locate specialized adapter specification if one exists based on config data
|
|
491
|
+
def adapter_spec(config)
|
|
492
|
+
dialect = (config[:dialect] || config[:driver]).to_s
|
|
493
|
+
::JdbcSpec.constants.map { |name| ::JdbcSpec.const_get name }.each do |constant|
|
|
494
|
+
if constant.respond_to? :adapter_matcher
|
|
495
|
+
spec = constant.adapter_matcher(dialect, config)
|
|
496
|
+
return spec if spec
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
nil
|
|
500
|
+
end
|
|
501
|
+
|
|
502
|
+
def modify_types(tp)
|
|
503
|
+
tp
|
|
504
|
+
end
|
|
505
|
+
|
|
506
|
+
def adapter_name #:nodoc:
|
|
507
|
+
'JDBC'
|
|
508
|
+
end
|
|
509
|
+
|
|
510
|
+
def supports_migrations?
|
|
511
|
+
true
|
|
512
|
+
end
|
|
513
|
+
|
|
514
|
+
def native_database_types #:nodoc:
|
|
515
|
+
@connection.native_database_types
|
|
516
|
+
end
|
|
517
|
+
|
|
518
|
+
def database_name #:nodoc:
|
|
519
|
+
@connection.database_name
|
|
520
|
+
end
|
|
521
|
+
|
|
522
|
+
def native_sql_to_type(tp)
|
|
523
|
+
if /^(.*?)\(([0-9]+)\)/ =~ tp
|
|
524
|
+
tname = $1
|
|
525
|
+
limit = $2.to_i
|
|
526
|
+
ntype = native_database_types
|
|
527
|
+
if ntype[:primary_key] == tp
|
|
528
|
+
return :primary_key,nil
|
|
529
|
+
else
|
|
530
|
+
ntype.each do |name,val|
|
|
531
|
+
if name == :primary_key
|
|
532
|
+
next
|
|
533
|
+
end
|
|
534
|
+
if val[:name].downcase == tname.downcase && (val[:limit].nil? || val[:limit].to_i == limit)
|
|
535
|
+
return name,limit
|
|
536
|
+
end
|
|
537
|
+
end
|
|
538
|
+
end
|
|
539
|
+
elsif /^(.*?)/ =~ tp
|
|
540
|
+
tname = $1
|
|
541
|
+
ntype = native_database_types
|
|
542
|
+
if ntype[:primary_key] == tp
|
|
543
|
+
return :primary_key,nil
|
|
544
|
+
else
|
|
545
|
+
ntype.each do |name,val|
|
|
546
|
+
if val[:name].downcase == tname.downcase && val[:limit].nil?
|
|
547
|
+
return name,nil
|
|
548
|
+
end
|
|
549
|
+
end
|
|
550
|
+
end
|
|
551
|
+
else
|
|
552
|
+
return :string,255
|
|
553
|
+
end
|
|
554
|
+
return nil,nil
|
|
555
|
+
end
|
|
556
|
+
|
|
557
|
+
def reconnect!
|
|
558
|
+
@connection.reconnect!
|
|
559
|
+
@connection
|
|
560
|
+
end
|
|
561
|
+
|
|
562
|
+
def disconnect!
|
|
563
|
+
@connection.disconnect!
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
def jdbc_select_all(sql, name = nil)
|
|
567
|
+
select(sql, name)
|
|
568
|
+
end
|
|
569
|
+
alias_chained_method :select_all, :query_cache, :jdbc_select_all
|
|
570
|
+
|
|
571
|
+
def select_rows(sql, name = nil)
|
|
572
|
+
rows = []
|
|
573
|
+
select(sql, name).each {|row| rows << row.values }
|
|
574
|
+
rows
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
def select_one(sql, name = nil)
|
|
578
|
+
select(sql, name).first
|
|
579
|
+
end
|
|
580
|
+
|
|
581
|
+
def execute(sql, name = nil)
|
|
582
|
+
log(sql, name) do
|
|
583
|
+
_execute(sql,name)
|
|
584
|
+
end
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
# we need to do it this way, to allow Rails stupid tests to always work
|
|
588
|
+
# even if we define a new execute method. Instead of mixing in a new
|
|
589
|
+
# execute, an _execute should be mixed in.
|
|
590
|
+
def _execute(sql, name = nil)
|
|
591
|
+
if JdbcConnection::select?(sql)
|
|
592
|
+
@connection.execute_query(sql)
|
|
593
|
+
elsif JdbcConnection::insert?(sql)
|
|
594
|
+
@connection.execute_insert(sql)
|
|
595
|
+
else
|
|
596
|
+
@connection.execute_update(sql)
|
|
597
|
+
end
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
def jdbc_update(sql, name = nil) #:nodoc:
|
|
601
|
+
execute(sql, name)
|
|
602
|
+
end
|
|
603
|
+
alias_chained_method :update, :query_dirty, :jdbc_update
|
|
604
|
+
|
|
605
|
+
def jdbc_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil)
|
|
606
|
+
id = execute(sql, name = nil)
|
|
607
|
+
id_value || id
|
|
608
|
+
end
|
|
609
|
+
alias_chained_method :insert, :query_dirty, :jdbc_insert
|
|
610
|
+
|
|
611
|
+
def jdbc_columns(table_name, name = nil)
|
|
612
|
+
@connection.columns(table_name.to_s)
|
|
613
|
+
end
|
|
614
|
+
alias_chained_method :columns, :query_cache, :jdbc_columns
|
|
615
|
+
|
|
616
|
+
def tables
|
|
617
|
+
@connection.tables
|
|
618
|
+
end
|
|
619
|
+
|
|
620
|
+
def indexes(table_name, name = nil, schema_name = nil)
|
|
621
|
+
@connection.indexes(table_name, name, schema_name)
|
|
622
|
+
end
|
|
623
|
+
|
|
624
|
+
def begin_db_transaction
|
|
625
|
+
@connection.begin
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
def commit_db_transaction
|
|
629
|
+
@connection.commit
|
|
630
|
+
end
|
|
631
|
+
|
|
632
|
+
def rollback_db_transaction
|
|
633
|
+
@connection.rollback
|
|
634
|
+
end
|
|
635
|
+
|
|
636
|
+
def write_large_object(*args)
|
|
637
|
+
@connection.write_large_object(*args)
|
|
638
|
+
end
|
|
639
|
+
|
|
640
|
+
def pk_and_sequence_for(table)
|
|
641
|
+
key = primary_key(table)
|
|
642
|
+
[key, nil] if key
|
|
643
|
+
end
|
|
644
|
+
|
|
645
|
+
def primary_key(table)
|
|
646
|
+
primary_keys(table).first
|
|
647
|
+
end
|
|
648
|
+
|
|
649
|
+
def primary_keys(table)
|
|
650
|
+
@connection.primary_keys(table)
|
|
651
|
+
end
|
|
652
|
+
|
|
653
|
+
private
|
|
654
|
+
def select(sql, name=nil)
|
|
655
|
+
log(sql, name) do
|
|
656
|
+
@connection.execute_query(sql)
|
|
657
|
+
end
|
|
658
|
+
end
|
|
659
|
+
end
|
|
660
|
+
end
|
|
661
|
+
end
|