activerecord-jdbc-adapter 1.3.0.beta1 → 1.3.0.beta2
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +12 -11
- data/.travis.yml +36 -7
- data/Appraisals +3 -3
- data/Gemfile +1 -1
- data/Gemfile.lock +13 -6
- data/History.txt +64 -0
- data/README.md +8 -1
- data/Rakefile +3 -1
- data/gemfiles/rails23.gemfile +1 -1
- data/gemfiles/rails23.gemfile.lock +6 -5
- data/gemfiles/rails30.gemfile +1 -1
- data/gemfiles/rails30.gemfile.lock +7 -6
- data/gemfiles/rails31.gemfile +1 -1
- data/gemfiles/rails31.gemfile.lock +6 -5
- data/gemfiles/rails32.gemfile +1 -1
- data/gemfiles/rails32.gemfile.lock +6 -5
- data/gemfiles/rails40.gemfile +2 -4
- data/gemfiles/rails40.gemfile.lock +37 -51
- data/lib/active_record/connection_adapters/as400_adapter.rb +2 -0
- data/lib/active_record/connection_adapters/db2_adapter.rb +1 -1
- data/lib/arel/visitors/db2.rb +5 -1
- data/lib/arel/visitors/hsqldb.rb +1 -0
- data/lib/arel/visitors/sql_server.rb +55 -13
- data/lib/arjdbc/db2/adapter.rb +197 -227
- data/lib/arjdbc/db2/as400.rb +124 -0
- data/lib/arjdbc/db2/connection_methods.rb +20 -1
- data/lib/arjdbc/derby/adapter.rb +17 -85
- data/lib/arjdbc/derby/connection_methods.rb +2 -1
- data/lib/arjdbc/discover.rb +55 -47
- data/lib/arjdbc/h2/adapter.rb +52 -18
- data/lib/arjdbc/h2/connection_methods.rb +10 -2
- data/lib/arjdbc/hsqldb/adapter.rb +33 -9
- data/lib/arjdbc/hsqldb/connection_methods.rb +10 -2
- data/lib/arjdbc/informix.rb +2 -1
- data/lib/arjdbc/jdbc.rb +5 -1
- data/lib/arjdbc/jdbc/adapter.rb +167 -89
- data/lib/arjdbc/jdbc/adapter_java.jar +0 -0
- data/lib/arjdbc/jdbc/adapter_require.rb +46 -0
- data/lib/arjdbc/jdbc/base_ext.rb +25 -3
- data/lib/arjdbc/jdbc/callbacks.rb +9 -8
- data/lib/arjdbc/jdbc/column.rb +8 -20
- data/lib/arjdbc/jdbc/connection.rb +69 -80
- data/lib/arjdbc/jdbc/extension.rb +6 -8
- data/lib/arjdbc/jdbc/jdbc.rake +3 -141
- data/lib/arjdbc/jdbc/rake_tasks.rb +3 -10
- data/lib/arjdbc/mssql/adapter.rb +108 -34
- data/lib/arjdbc/mssql/connection_methods.rb +3 -1
- data/lib/arjdbc/mssql/limit_helpers.rb +3 -2
- data/lib/arjdbc/mssql/lock_helpers.rb +5 -1
- data/lib/arjdbc/mysql/adapter.rb +127 -70
- data/lib/arjdbc/mysql/connection_methods.rb +5 -2
- data/lib/arjdbc/oracle/adapter.rb +124 -94
- data/lib/arjdbc/oracle/connection_methods.rb +2 -1
- data/lib/arjdbc/postgresql/adapter.rb +99 -67
- data/lib/arjdbc/postgresql/column_cast.rb +3 -5
- data/lib/arjdbc/postgresql/connection_methods.rb +6 -6
- data/lib/arjdbc/railtie.rb +3 -1
- data/lib/arjdbc/sqlite3/adapter.rb +60 -43
- data/lib/arjdbc/sqlite3/connection_methods.rb +9 -9
- data/lib/arjdbc/sybase.rb +1 -1
- data/lib/arjdbc/tasks.rb +13 -0
- data/lib/arjdbc/tasks/database_tasks.rb +50 -0
- data/lib/arjdbc/tasks/databases.rake +89 -0
- data/lib/arjdbc/tasks/databases3.rake +203 -0
- data/lib/arjdbc/tasks/databases4.rake +39 -0
- data/lib/arjdbc/tasks/db2_database_tasks.rb +104 -0
- data/lib/arjdbc/tasks/derby_database_tasks.rb +95 -0
- data/lib/arjdbc/tasks/h2_database_tasks.rb +29 -0
- data/lib/arjdbc/tasks/hsqldb_database_tasks.rb +70 -0
- data/lib/arjdbc/tasks/jdbc_database_tasks.rb +122 -0
- data/lib/arjdbc/tasks/mssql_database_tasks.rb +36 -0
- data/lib/arjdbc/tasks/oracle/enhanced_structure_dump.rb +297 -0
- data/lib/arjdbc/tasks/oracle_database_tasks.rb +62 -0
- data/lib/arjdbc/version.rb +1 -1
- data/pom.xml +11 -12
- data/rails_generators/jdbc_generator.rb +1 -1
- data/rails_generators/templates/config/initializers/jdbc.rb +8 -5
- data/rails_generators/templates/lib/tasks/jdbc.rake +7 -4
- data/rakelib/02-test.rake +42 -15
- data/rakelib/compile.rake +29 -2
- data/rakelib/db.rake +2 -1
- data/rakelib/rails.rake +23 -6
- data/src/java/arjdbc/ArJdbcModule.java +175 -0
- data/src/java/arjdbc/db2/DB2Module.java +2 -1
- data/src/java/arjdbc/derby/DerbyModule.java +5 -24
- data/src/java/arjdbc/hsqldb/HSQLDBModule.java +3 -2
- data/src/java/arjdbc/jdbc/AdapterJavaService.java +3 -46
- data/src/java/arjdbc/jdbc/RubyJdbcConnection.java +1001 -259
- data/src/java/arjdbc/mssql/MSSQLModule.java +2 -1
- data/src/java/arjdbc/mysql/MySQLModule.java +4 -3
- data/src/java/arjdbc/mysql/MySQLRubyJdbcConnection.java +12 -7
- data/src/java/arjdbc/oracle/OracleModule.java +2 -1
- data/src/java/arjdbc/sqlite3/SQLite3Module.java +2 -1
- data/src/java/arjdbc/sqlite3/SQLite3RubyJdbcConnection.java +12 -0
- data/test/db/db2.rb +14 -7
- data/test/db/db2/rake_test.rb +82 -0
- data/test/db/db2/rake_test_data.sql +35 -0
- data/test/db/db2/simple_test.rb +20 -0
- data/test/db/db2/unit_test.rb +3 -1
- data/test/db/derby.rb +7 -5
- data/test/db/derby/rake_test.rb +96 -0
- data/test/db/derby/simple_test.rb +10 -2
- data/test/db/h2.rb +6 -8
- data/test/db/h2/identity_column_test.rb +35 -0
- data/test/db/h2/offset_test.rb +49 -0
- data/test/db/h2/rake_test.rb +98 -0
- data/test/db/h2/schema_dump_test.rb +5 -1
- data/test/db/hsqldb.rb +6 -10
- data/test/db/hsqldb/rake_test.rb +101 -0
- data/test/db/hsqldb/schema_dump_test.rb +5 -1
- data/test/db/hsqldb/simple_test.rb +8 -0
- data/test/db/jndi_config.rb +1 -3
- data/test/db/jndi_pooled_config.rb +1 -3
- data/test/db/mssql/limit_offset_test.rb +23 -14
- data/test/db/mssql/rake_test.rb +143 -0
- data/test/db/mysql/_rails_test_mysql.32.out +1069 -1252
- data/test/db/mysql/nonstandard_primary_key_test.rb +21 -24
- data/test/db/mysql/rake_test.rb +97 -0
- data/test/db/mysql/schema_dump_test.rb +11 -11
- data/test/db/mysql/simple_test.rb +52 -3
- data/test/db/mysql/statement_escaping_test.rb +46 -0
- data/test/db/oracle/rake_test.rb +100 -0
- data/test/db/oracle/simple_test.rb +48 -0
- data/test/db/postgres/_rails_test_postgres.32.out +998 -1370
- data/test/db/postgres/active_schema_unit_test.rb +68 -0
- data/test/db/postgres/connection_test.rb +10 -2
- data/test/db/postgres/data_types_test.rb +2 -2
- data/test/db/postgres/ltree_test.rb +6 -5
- data/test/db/postgres/native_types_test.rb +1 -5
- data/test/db/postgres/rake_test.rb +117 -0
- data/test/db/postgres/schema_dump_test.rb +9 -2
- data/test/db/postgres/schema_test.rb +4 -2
- data/test/db/postgres/simple_test.rb +57 -16
- data/test/db/sqlite3.rb +3 -10
- data/test/db/sqlite3/_rails_test_sqlite3.32.out +1070 -1298
- data/test/db/sqlite3/rake_test.rb +71 -0
- data/test/db/sqlite3/simple_test.rb +9 -9
- data/test/has_many_through.rb +4 -1
- data/test/jdbc/db2.rb +14 -1
- data/test/jdbc_column_test.rb +23 -0
- data/test/{generic_jdbc_connection_test.rb → jdbc_connection_test.rb} +22 -17
- data/test/jndi_callbacks_test.rb +26 -28
- data/test/jndi_test.rb +7 -16
- data/test/models/data_types.rb +2 -1
- data/test/models/thing.rb +1 -0
- data/test/rails/mysql.rb +13 -0
- data/test/rails/sqlite3/version.rb +6 -0
- data/test/rails_stub.rb +31 -0
- data/test/rake_test_support.rb +298 -0
- data/test/serialize.rb +2 -4
- data/test/{helper.rb → shared_helper.rb} +0 -0
- data/test/simple.rb +167 -93
- data/test/test_helper.rb +52 -16
- metadata +388 -354
- data/lib/pg.rb +0 -26
- data/test/abstract_db_create.rb +0 -139
- data/test/activerecord/connection_adapters/type_conversion_test.rb +0 -36
- data/test/db/mssql/db_create_test.rb +0 -29
- data/test/db/mysql/db_create_test.rb +0 -33
- data/test/db/postgres/db_create_test.rb +0 -44
- data/test/db/postgres/db_drop_test.rb +0 -17
data/lib/arjdbc/h2/adapter.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
ArJdbc.load_java_part :H2
|
1
2
|
require 'arjdbc/hsqldb/adapter'
|
2
3
|
|
3
4
|
module ArJdbc
|
@@ -11,11 +12,11 @@ module ArJdbc
|
|
11
12
|
def self.column_selector
|
12
13
|
[ /\.h2\./i, lambda { |cfg, column| column.extend(::ArJdbc::H2::Column) } ]
|
13
14
|
end
|
14
|
-
|
15
|
+
|
15
16
|
module Column
|
16
|
-
|
17
|
+
|
17
18
|
private
|
18
|
-
|
19
|
+
|
19
20
|
def extract_limit(sql_type)
|
20
21
|
limit = super
|
21
22
|
case @sql_type = sql_type.downcase
|
@@ -34,14 +35,14 @@ module ArJdbc
|
|
34
35
|
when /blob|image|oid/i then @sql_type = 'blob'; limit = nil
|
35
36
|
when /clob|text/i then @sql_type = 'clob'; limit = nil
|
36
37
|
# NOTE: use lower-case due SchemaDumper not handling it's decimal/integer
|
37
|
-
# optimization case-insensitively due : column.type == :integer &&
|
38
|
+
# optimization case-insensitively due : column.type == :integer &&
|
38
39
|
# [/^numeric/, /^decimal/].any? { |e| e.match(column.sql_type) }
|
39
40
|
when /^decimal\(65535,32767\)/i
|
40
41
|
@sql_type = 'decimal'; nil
|
41
42
|
end
|
42
43
|
limit
|
43
44
|
end
|
44
|
-
|
45
|
+
|
45
46
|
def simplified_type(field_type)
|
46
47
|
case field_type
|
47
48
|
when /^bit|bool/i then :boolean
|
@@ -54,7 +55,7 @@ module ArJdbc
|
|
54
55
|
super
|
55
56
|
end
|
56
57
|
end
|
57
|
-
|
58
|
+
|
58
59
|
# Post process default value from JDBC into a Rails-friendly format (columns{-internal})
|
59
60
|
def default_value(value)
|
60
61
|
# H2 auto-generated key default value
|
@@ -63,11 +64,11 @@ module ArJdbc
|
|
63
64
|
return $1 if value =~ /^'(.*)'$/
|
64
65
|
value
|
65
66
|
end
|
66
|
-
|
67
|
+
|
67
68
|
end
|
68
|
-
|
69
|
+
|
69
70
|
ADAPTER_NAME = 'H2' # :nodoc:
|
70
|
-
|
71
|
+
|
71
72
|
def adapter_name # :nodoc:
|
72
73
|
ADAPTER_NAME
|
73
74
|
end
|
@@ -79,14 +80,14 @@ module ArJdbc
|
|
79
80
|
'jdbch2' => ::Arel::Visitors::HSQLDB,
|
80
81
|
})
|
81
82
|
end
|
82
|
-
|
83
|
+
|
83
84
|
# #deprecated
|
84
85
|
def h2_adapter # :nodoc:
|
85
86
|
true
|
86
87
|
end
|
87
88
|
|
88
89
|
NATIVE_DATABASE_TYPES = {
|
89
|
-
:primary_key => "
|
90
|
+
:primary_key => "bigint identity",
|
90
91
|
:boolean => { :name => "boolean" },
|
91
92
|
:tinyint => { :name => "tinyint", :limit => 1 },
|
92
93
|
:smallint => { :name => "smallint", :limit => 2 },
|
@@ -115,11 +116,11 @@ module ArJdbc
|
|
115
116
|
def native_database_types
|
116
117
|
NATIVE_DATABASE_TYPES.dup
|
117
118
|
end
|
118
|
-
|
119
|
+
|
119
120
|
def modify_types(types)
|
120
121
|
types
|
121
122
|
end
|
122
|
-
|
123
|
+
|
123
124
|
def type_to_sql(type, limit = nil, precision = nil, scale = nil)
|
124
125
|
case type.to_sym
|
125
126
|
when :integer
|
@@ -146,6 +147,10 @@ module ArJdbc
|
|
146
147
|
super
|
147
148
|
end
|
148
149
|
end
|
150
|
+
|
151
|
+
def empty_insert_statement_value
|
152
|
+
"VALUES ()"
|
153
|
+
end
|
149
154
|
|
150
155
|
def tables
|
151
156
|
@connection.tables(nil, h2_schema)
|
@@ -164,7 +169,7 @@ module ArJdbc
|
|
164
169
|
def current_schema
|
165
170
|
execute('CALL SCHEMA()')[0].values[0]
|
166
171
|
end
|
167
|
-
|
172
|
+
|
168
173
|
def quote(value, column = nil) # :nodoc:
|
169
174
|
case value
|
170
175
|
when String
|
@@ -177,9 +182,9 @@ module ArJdbc
|
|
177
182
|
super
|
178
183
|
end
|
179
184
|
end
|
180
|
-
|
185
|
+
|
181
186
|
# EXPLAIN support :
|
182
|
-
|
187
|
+
|
183
188
|
def supports_explain?; true; end
|
184
189
|
|
185
190
|
def explain(arel, binds = [])
|
@@ -188,8 +193,37 @@ module ArJdbc
|
|
188
193
|
raw_result[0].values.join("\n") # [ "SELECT \n ..." ].to_s
|
189
194
|
end
|
190
195
|
|
191
|
-
|
196
|
+
def structure_dump
|
197
|
+
execute('SCRIPT SIMPLE').map do |result|
|
198
|
+
# [ { 'script' => SQL }, { 'script' ... }, ... ]
|
199
|
+
case sql = result.first[1] # ['script']
|
200
|
+
when /CREATE USER IF NOT EXISTS SA/i then nil
|
201
|
+
else sql
|
202
|
+
end
|
203
|
+
end.compact.join("\n\n")
|
204
|
+
end
|
205
|
+
|
206
|
+
def structure_load(dump)
|
207
|
+
dump.each_line("\n\n") { |ddl| execute(ddl) }
|
208
|
+
end
|
209
|
+
|
210
|
+
def shutdown
|
211
|
+
execute 'SHUTDOWN COMPACT'
|
212
|
+
end
|
213
|
+
|
214
|
+
def recreate_database(name = nil, options = {}) # :nodoc:
|
215
|
+
drop_database(name)
|
216
|
+
create_database(name, options)
|
217
|
+
end
|
192
218
|
|
219
|
+
def create_database(name = nil, options = {}); end # :nodoc:
|
220
|
+
|
221
|
+
def drop_database(name = nil) # :nodoc:
|
222
|
+
execute('DROP ALL OBJECTS')
|
223
|
+
end
|
224
|
+
|
225
|
+
private
|
226
|
+
|
193
227
|
def change_column_null(table_name, column_name, null, default = nil)
|
194
228
|
if !null && !default.nil?
|
195
229
|
execute("UPDATE #{table_name} SET #{column_name}=#{quote(default)} WHERE #{column_name} IS NULL")
|
@@ -204,6 +238,6 @@ module ArJdbc
|
|
204
238
|
def h2_schema
|
205
239
|
@config[:schema] || ''
|
206
240
|
end
|
207
|
-
|
241
|
+
|
208
242
|
end
|
209
243
|
end
|
@@ -6,9 +6,17 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
6
6
|
rescue LoadError # assuming driver.jar is on the class-path
|
7
7
|
end
|
8
8
|
|
9
|
-
config[:url] ||=
|
9
|
+
config[:url] ||= begin
|
10
|
+
db = config[:database]
|
11
|
+
if db[0, 4] == 'mem:' || db[0, 5] == 'file:' || db[0, 5] == 'hsql:'
|
12
|
+
"jdbc:h2:#{db}"
|
13
|
+
else
|
14
|
+
"jdbc:h2:file:#{db}"
|
15
|
+
end
|
16
|
+
end
|
10
17
|
config[:driver] ||= defined?(::Jdbc::H2.driver_name) ? ::Jdbc::H2.driver_name : 'org.h2.Driver'
|
11
|
-
config[:adapter_spec]
|
18
|
+
config[:adapter_spec] ||= ::ArJdbc::H2
|
19
|
+
|
12
20
|
embedded_driver(config)
|
13
21
|
end
|
14
22
|
alias_method :jdbch2_connection, :h2_connection
|
@@ -1,3 +1,4 @@
|
|
1
|
+
ArJdbc.load_java_part :HSQLDB
|
1
2
|
require 'arjdbc/hsqldb/explain_support'
|
2
3
|
|
3
4
|
module ArJdbc
|
@@ -188,6 +189,12 @@ module ArJdbc
|
|
188
189
|
end
|
189
190
|
end
|
190
191
|
|
192
|
+
def empty_insert_statement_value
|
193
|
+
# on HSQLDB only work with tables that have a default value for each
|
194
|
+
# and every column ... you'll need to avoid `Model.create!` on 4.0
|
195
|
+
'DEFAULT VALUES'
|
196
|
+
end
|
197
|
+
|
191
198
|
# filter out system tables (that otherwise end up in db/schema.rb)
|
192
199
|
# JdbcConnection#tables
|
193
200
|
# now takes an optional block filter so we can screen out
|
@@ -201,19 +208,36 @@ module ArJdbc
|
|
201
208
|
def remove_index(table_name, options = {})
|
202
209
|
execute "DROP INDEX #{quote_column_name(index_name(table_name, options))}"
|
203
210
|
end
|
211
|
+
|
212
|
+
def structure_dump
|
213
|
+
execute('SCRIPT').map do |result|
|
214
|
+
# [ { 'command' => SQL }, { 'command' ... }, ... ]
|
215
|
+
case sql = result.first[1] # ['command']
|
216
|
+
when /CREATE USER SA PASSWORD DIGEST .*?/i then nil
|
217
|
+
when /CREATE SCHEMA PUBLIC AUTHORIZATION DBA/i then nil
|
218
|
+
when /GRANT DBA TO SA/i then nil
|
219
|
+
else sql
|
220
|
+
end
|
221
|
+
end.compact.join("\n\n")
|
222
|
+
end
|
204
223
|
|
205
|
-
def
|
206
|
-
|
224
|
+
def structure_load(dump)
|
225
|
+
dump.each_line("\n\n") { |ddl| execute(ddl) }
|
207
226
|
end
|
208
227
|
|
209
|
-
|
210
|
-
|
211
|
-
# avoiding method_missing error
|
212
|
-
def create_database(name)
|
228
|
+
def shutdown
|
229
|
+
execute 'SHUTDOWN'
|
213
230
|
end
|
214
|
-
|
215
|
-
def
|
216
|
-
|
231
|
+
|
232
|
+
def recreate_database(name = nil, options = {}) # :nodoc:
|
233
|
+
drop_database(name)
|
234
|
+
create_database(name, options)
|
235
|
+
end
|
236
|
+
|
237
|
+
def create_database(name = nil, options = {}); end # :nodoc:
|
238
|
+
|
239
|
+
def drop_database(name = nil) # :nodoc:
|
240
|
+
execute('DROP SCHEMA PUBLIC CASCADE')
|
217
241
|
end
|
218
242
|
|
219
243
|
end
|
@@ -6,10 +6,18 @@ ArJdbc::ConnectionMethods.module_eval do
|
|
6
6
|
rescue LoadError # assuming driver.jar is on the class-path
|
7
7
|
end
|
8
8
|
|
9
|
-
config[:url] ||=
|
9
|
+
config[:url] ||= begin
|
10
|
+
db = config[:database]
|
11
|
+
if db[0, 4] == 'mem:' || db[0, 5] == 'file:' || db[0, 5] == 'hsql:'
|
12
|
+
"jdbc:hsqldb:#{db}"
|
13
|
+
else
|
14
|
+
"jdbc:hsqldb:file:#{db}"
|
15
|
+
end
|
16
|
+
end
|
10
17
|
config[:driver] ||= defined?(::Jdbc::HSQLDB.driver_name) ? ::Jdbc::HSQLDB.driver_name : 'org.hsqldb.jdbcDriver'
|
11
|
-
config[:adapter_spec]
|
18
|
+
config[:adapter_spec] ||= ::ArJdbc::HSQLDB
|
12
19
|
config[:connection_alive_sql] ||= 'CALL PI()' # does not like 'SELECT 1'
|
20
|
+
|
13
21
|
embedded_driver(config)
|
14
22
|
end
|
15
23
|
alias_method :jdbchsqldb_connection, :hsqldb_connection
|
data/lib/arjdbc/informix.rb
CHANGED
data/lib/arjdbc/jdbc.rb
CHANGED
data/lib/arjdbc/jdbc/adapter.rb
CHANGED
@@ -16,31 +16,42 @@ module ActiveRecord
|
|
16
16
|
module ConnectionAdapters
|
17
17
|
class JdbcAdapter < AbstractAdapter
|
18
18
|
extend ShadowCoreMethods
|
19
|
-
|
19
|
+
|
20
|
+
include JdbcConnectionPoolCallbacks
|
20
21
|
|
21
22
|
attr_reader :config
|
22
|
-
|
23
|
-
def initialize(connection, logger, config)
|
24
|
-
|
25
|
-
|
26
|
-
config[:adapter_spec] ||= spec
|
27
|
-
unless connection
|
28
|
-
connection_class = jdbc_connection_class spec
|
29
|
-
connection = connection_class.new config
|
23
|
+
|
24
|
+
def initialize(connection, logger, config = nil) # (logger, config)
|
25
|
+
if config.nil? && logger.respond_to?(:key?) # only 2 arguments given
|
26
|
+
config, logger, connection = logger, connection, nil
|
30
27
|
end
|
28
|
+
|
29
|
+
@config = config
|
30
|
+
|
31
|
+
@config[:adapter_spec] = adapter_spec(@config) unless @config.key?(:adapter_spec)
|
32
|
+
spec = @config[:adapter_spec]
|
33
|
+
|
34
|
+
connection ||= jdbc_connection_class(spec).new(@config)
|
35
|
+
|
31
36
|
super(connection, logger)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
+
|
38
|
+
# kind of like `extend ArJdbc::MyDB if self.class == JdbcAdapter` :
|
39
|
+
klass = @config[:adapter_class]
|
40
|
+
extend spec if spec && ( ! klass || klass == JdbcAdapter)
|
41
|
+
|
42
|
+
connection.adapter = self # prepares native database types
|
43
|
+
|
44
|
+
# NOTE: should not be necessary for JNDI due reconnect! on checkout :
|
45
|
+
configure_connection if respond_to?(:configure_connection)
|
46
|
+
|
37
47
|
JndiConnectionPoolCallbacks.prepare(self, connection)
|
48
|
+
|
49
|
+
@visitor = new_visitor(@config) # nil if no AREL (AR-2.3)
|
38
50
|
end
|
39
|
-
|
51
|
+
|
40
52
|
def jdbc_connection_class(spec)
|
41
53
|
connection_class = spec.jdbc_connection_class if spec && spec.respond_to?(:jdbc_connection_class)
|
42
|
-
connection_class
|
43
|
-
connection_class
|
54
|
+
connection_class ? connection_class : ::ActiveRecord::ConnectionAdapters::JdbcConnection
|
44
55
|
end
|
45
56
|
|
46
57
|
def jdbc_column_class
|
@@ -67,18 +78,17 @@ module ActiveRecord
|
|
67
78
|
# Locate specialized adapter specification if one exists based on config data
|
68
79
|
def adapter_spec(config)
|
69
80
|
dialect = (config[:dialect] || config[:driver]).to_s
|
70
|
-
::ArJdbc.
|
71
|
-
constant = ::ArJdbc.const_get(constant) # e.g. ArJdbc::MySQL
|
72
|
-
|
81
|
+
::ArJdbc.modules.each do |constant| # e.g. ArJdbc::MySQL
|
73
82
|
if constant.respond_to?(:adapter_matcher)
|
74
83
|
spec = constant.adapter_matcher(dialect, config)
|
75
84
|
return spec if spec
|
76
85
|
end
|
77
86
|
end
|
78
87
|
|
79
|
-
if config[:jndi] && ! config[:dialect]
|
88
|
+
if (config[:jndi] || config[:data_source]) && ! config[:dialect]
|
80
89
|
begin
|
81
|
-
data_source =
|
90
|
+
data_source = config[:data_source] ||
|
91
|
+
Java::JavaxNaming::InitialContext.new.lookup(config[:jndi])
|
82
92
|
connection = data_source.getConnection
|
83
93
|
config[:dialect] = connection.getMetaData.getDatabaseProductName
|
84
94
|
rescue Java::JavaSql::SQLException => e
|
@@ -97,41 +107,99 @@ module ActiveRecord
|
|
97
107
|
types
|
98
108
|
end
|
99
109
|
|
100
|
-
def adapter_name
|
110
|
+
def adapter_name # :nodoc:
|
101
111
|
'JDBC'
|
102
112
|
end
|
103
113
|
|
114
|
+
def self.arel2_visitors(config)
|
115
|
+
{ 'jdbc' => ::Arel::Visitors::ToSql }
|
116
|
+
end
|
117
|
+
|
118
|
+
# NOTE: called from {ConnectionPool#checkout} (up till AR-3.2)
|
104
119
|
def self.visitor_for(pool)
|
105
120
|
config = pool.spec.config
|
106
|
-
adapter = config[:adapter]
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
121
|
+
adapter = config[:adapter] # e.g. "sqlite3" (based on {#adapter_name})
|
122
|
+
unless visitor = ::Arel::Visitors::VISITORS[ adapter ]
|
123
|
+
adapter_spec = config[:adapter_spec] || self # e.g. ArJdbc::SQLite3
|
124
|
+
if adapter =~ /^(jdbc|jndi)$/
|
125
|
+
visitor = adapter_spec.arel2_visitors(config).values.first
|
126
|
+
else
|
127
|
+
visitor = adapter_spec.arel2_visitors(config)[adapter]
|
128
|
+
end
|
112
129
|
end
|
130
|
+
( prepared_statements?(config) ? visitor : bind_substitution(visitor) ).new(pool)
|
113
131
|
end
|
114
132
|
|
115
|
-
def self.
|
116
|
-
|
133
|
+
def self.configure_arel2_visitors(config)
|
134
|
+
visitors = ::Arel::Visitors::VISITORS
|
135
|
+
klass = config[:adapter_spec]
|
136
|
+
klass = self unless klass.respond_to?(:arel2_visitors)
|
137
|
+
visitor = nil
|
138
|
+
klass.arel2_visitors(config).each do |name, arel|
|
139
|
+
visitors[name] = ( visitor = arel )
|
140
|
+
end
|
141
|
+
if visitor && config[:adapter] =~ /^(jdbc|jndi)$/
|
142
|
+
visitors[ config[:adapter] ] = visitor
|
143
|
+
end
|
144
|
+
visitor
|
117
145
|
end
|
118
146
|
|
119
|
-
def
|
120
|
-
|
121
|
-
|
122
|
-
visitor =
|
123
|
-
|
124
|
-
|
125
|
-
visitor = v
|
126
|
-
visitors[k] = v
|
147
|
+
def new_visitor(config = self.config)
|
148
|
+
visitor = ::Arel::Visitors::VISITORS[ adapter = config[:adapter] ]
|
149
|
+
unless visitor
|
150
|
+
visitor = self.class.configure_arel2_visitors(config)
|
151
|
+
unless visitor
|
152
|
+
raise "no visitor configured for adapter: #{adapter.inspect}"
|
127
153
|
end
|
128
|
-
|
129
|
-
|
154
|
+
end
|
155
|
+
( prepared_statements? ? visitor : bind_substitution(visitor) ).new(self)
|
156
|
+
end
|
157
|
+
protected :new_visitor
|
158
|
+
|
159
|
+
unless defined? ::Arel::Visitors::VISITORS # NO-OP when no AREL (AR-2.3)
|
160
|
+
def self.configure_arel2_visitors(config); end
|
161
|
+
def new_visitor(config = self.config); end
|
162
|
+
end
|
163
|
+
|
164
|
+
@@bind_substitutions = nil
|
165
|
+
|
166
|
+
# @return a {#Arel::Visitors::BindVisitor} class for given visitor type
|
167
|
+
def self.bind_substitution(visitor)
|
168
|
+
# NOTE: similar convention as in AR (but no base substitution type) :
|
169
|
+
# class BindSubstitution < ::Arel::Visitors::ToSql
|
170
|
+
# include ::Arel::Visitors::BindVisitor
|
171
|
+
# end
|
172
|
+
return const_get(:BindSubstitution) if const_defined?(:BindSubstitution)
|
173
|
+
|
174
|
+
@@bind_substitutions ||= Java::JavaUtil::HashMap.new
|
175
|
+
unless bind_visitor = @@bind_substitutions.get(visitor)
|
176
|
+
@@bind_substitutions.synchronized do
|
177
|
+
unless @@bind_substitutions.get(visitor)
|
178
|
+
bind_visitor = Class.new(visitor) do
|
179
|
+
include ::Arel::Visitors::BindVisitor
|
180
|
+
end
|
181
|
+
@@bind_substitutions.put(visitor, bind_visitor)
|
182
|
+
end
|
130
183
|
end
|
131
|
-
|
184
|
+
bind_visitor = @@bind_substitutions.get(visitor)
|
132
185
|
end
|
186
|
+
bind_visitor
|
133
187
|
end
|
134
|
-
|
188
|
+
|
189
|
+
begin
|
190
|
+
require 'arel/visitors/bind_visitor'
|
191
|
+
rescue LoadError # AR-3.0
|
192
|
+
def self.bind_substitution(visitor); visitor; end
|
193
|
+
end
|
194
|
+
|
195
|
+
def bind_substitution(visitor); self.class.bind_substitution(visitor); end
|
196
|
+
private :bind_substitution
|
197
|
+
|
198
|
+
# @override default implementation (does nothing silently)
|
199
|
+
def structure_dump
|
200
|
+
raise NotImplementedError, "structure_dump not supported"
|
201
|
+
end
|
202
|
+
|
135
203
|
def is_a?(klass) # :nodoc:
|
136
204
|
# This is to fake out current_adapter? conditional logic in AR tests
|
137
205
|
if Class === klass && klass.name =~ /#{adapter_name}Adapter$/i
|
@@ -145,11 +213,11 @@ module ActiveRecord
|
|
145
213
|
true
|
146
214
|
end
|
147
215
|
|
148
|
-
def native_database_types
|
216
|
+
def native_database_types # :nodoc:
|
149
217
|
@connection.native_database_types
|
150
218
|
end
|
151
219
|
|
152
|
-
def database_name
|
220
|
+
def database_name # :nodoc:
|
153
221
|
@connection.database_name
|
154
222
|
end
|
155
223
|
|
@@ -193,8 +261,7 @@ module ActiveRecord
|
|
193
261
|
end
|
194
262
|
|
195
263
|
def reconnect!
|
196
|
-
@connection.reconnect!
|
197
|
-
configure_connection if respond_to?(:configure_connection)
|
264
|
+
@connection.reconnect! # handles adapter.configure_connection
|
198
265
|
@connection
|
199
266
|
end
|
200
267
|
|
@@ -207,61 +274,71 @@ module ActiveRecord
|
|
207
274
|
def jdbc_insert(sql, name = nil, pk = nil, id_value = nil, sequence_name = nil, binds = []) # :nodoc:
|
208
275
|
insert_sql(sql, name, pk, id_value, sequence_name, binds)
|
209
276
|
end
|
277
|
+
alias_chained_method :insert, :query_dirty, :jdbc_insert
|
210
278
|
|
211
279
|
def jdbc_update(sql, name = nil, binds = []) # :nodoc:
|
212
280
|
execute(sql, name, binds)
|
213
281
|
end
|
282
|
+
alias_chained_method :update, :query_dirty, :jdbc_update
|
214
283
|
|
215
284
|
def jdbc_select_all(sql, name = nil, binds = []) # :nodoc:
|
216
285
|
select(sql, name, binds)
|
217
286
|
end
|
218
|
-
|
219
|
-
# Allow query caching to work even when we override alias_method_chain'd methods
|
220
287
|
alias_chained_method :select_all, :query_cache, :jdbc_select_all
|
221
|
-
alias_chained_method :update, :query_dirty, :jdbc_update
|
222
|
-
alias_chained_method :insert, :query_dirty, :jdbc_insert
|
223
288
|
|
224
289
|
end
|
225
|
-
|
226
|
-
def
|
290
|
+
|
291
|
+
def columns(table_name, name = nil)
|
227
292
|
@connection.columns(table_name.to_s)
|
228
293
|
end
|
229
|
-
alias_chained_method :columns, :query_cache, :jdbc_columns
|
230
294
|
|
231
295
|
# Executes +sql+ statement in the context of this connection using
|
232
296
|
# +binds+ as the bind substitutes. +name+ is logged along with
|
233
297
|
# the executed +sql+ statement.
|
234
298
|
def exec_query(sql, name = 'SQL', binds = []) # :nodoc:
|
235
|
-
|
299
|
+
sql = to_sql(sql, binds)
|
300
|
+
if prepared_statements?
|
301
|
+
log(sql, name, binds) { @connection.execute_query(sql, binds) }
|
302
|
+
else
|
303
|
+
sql = suble_binds(sql, binds)
|
304
|
+
log(sql, name) { @connection.execute_query(sql) }
|
305
|
+
end
|
236
306
|
end
|
237
307
|
|
238
308
|
# Executes insert +sql+ statement in the context of this connection using
|
239
309
|
# +binds+ as the bind substitutes. +name+ is the logged along with
|
240
310
|
# the executed +sql+ statement.
|
241
311
|
def exec_insert(sql, name, binds, pk = nil, sequence_name = nil) # :nodoc:
|
242
|
-
|
312
|
+
sql = suble_binds to_sql(sql, binds), binds
|
313
|
+
log(sql, name || 'SQL') { @connection.execute_insert(sql) }
|
243
314
|
end
|
244
315
|
|
245
316
|
# Executes delete +sql+ statement in the context of this connection using
|
246
317
|
# +binds+ as the bind substitutes. +name+ is the logged along with
|
247
318
|
# the executed +sql+ statement.
|
248
319
|
def exec_delete(sql, name, binds) # :nodoc:
|
249
|
-
|
320
|
+
sql = suble_binds to_sql(sql, binds), binds
|
321
|
+
log(sql, name || 'SQL') { @connection.execute_delete(sql) }
|
250
322
|
end
|
251
323
|
|
252
324
|
# Executes update +sql+ statement in the context of this connection using
|
253
325
|
# +binds+ as the bind substitutes. +name+ is the logged along with
|
254
326
|
# the executed +sql+ statement.
|
255
327
|
def exec_update(sql, name, binds) # :nodoc:
|
256
|
-
|
328
|
+
sql = suble_binds to_sql(sql, binds), binds
|
329
|
+
log(sql, name || 'SQL') { @connection.execute_update(sql) }
|
257
330
|
end
|
258
331
|
|
259
332
|
# Similar to {#exec_query} except it returns "raw" results in an array
|
260
333
|
# where each rows is a hash with keys as columns (just like Rails used to
|
261
334
|
# do up until 3.0) instead of wrapping them in a {#ActiveRecord::Result}.
|
262
335
|
def exec_query_raw(sql, name = 'SQL', binds = [], &block) # :nodoc:
|
263
|
-
|
264
|
-
|
336
|
+
sql = to_sql(sql, binds)
|
337
|
+
if prepared_statements?
|
338
|
+
log(sql, name, binds) { @connection.execute_query_raw(sql, binds, &block) }
|
339
|
+
else
|
340
|
+
sql = suble_binds(sql, binds)
|
341
|
+
log(sql, name) { @connection.execute_query_raw(sql, &block) }
|
265
342
|
end
|
266
343
|
end
|
267
344
|
|
@@ -289,7 +366,7 @@ module ActiveRecord
|
|
289
366
|
|
290
367
|
# Executes the SQL statement in the context of this connection.
|
291
368
|
def execute(sql, name = nil, binds = [])
|
292
|
-
sql = to_sql(sql, binds)
|
369
|
+
sql = suble_binds to_sql(sql, binds), binds
|
293
370
|
if name == :skip_logging
|
294
371
|
_execute(sql, name)
|
295
372
|
else
|
@@ -304,7 +381,7 @@ module ActiveRecord
|
|
304
381
|
|
305
382
|
# Executes the SQL statement in the context of this connection.
|
306
383
|
def execute(sql, name = nil, binds = [])
|
307
|
-
sql = to_sql(sql, binds)
|
384
|
+
sql = suble_binds to_sql(sql, binds), binds
|
308
385
|
if name == :skip_logging
|
309
386
|
_execute(sql, name)
|
310
387
|
else
|
@@ -386,37 +463,28 @@ module ActiveRecord
|
|
386
463
|
if ActiveRecord::VERSION::MAJOR == 3 && ActiveRecord::VERSION::MINOR == 0
|
387
464
|
|
388
465
|
#attr_reader :visitor unless method_defined?(:visitor) # not in 3.0
|
389
|
-
|
466
|
+
|
390
467
|
# Converts an AREL AST to SQL.
|
391
468
|
def to_sql(arel, binds = [])
|
392
|
-
# NOTE: can not handle `visitor.accept(arel.ast)` right
|
393
|
-
|
394
|
-
sql = arel.respond_to?(:to_sql) ? arel.send(:to_sql) : arel
|
395
|
-
return sql if binds.blank?
|
396
|
-
sql.gsub('?') { quote(*binds.shift.reverse) }
|
469
|
+
# NOTE: can not handle `visitor.accept(arel.ast)` right
|
470
|
+
arel.respond_to?(:to_sql) ? arel.send(:to_sql) : arel
|
397
471
|
end
|
398
472
|
|
399
473
|
elsif ActiveRecord::VERSION::MAJOR >= 3 # AR >= 3.1 or 4.0
|
400
|
-
|
474
|
+
|
401
475
|
# Converts an AREL AST to SQL.
|
402
476
|
def to_sql(arel, binds = [])
|
403
477
|
if arel.respond_to?(:ast)
|
404
478
|
visitor.accept(arel.ast) { quote(*binds.shift.reverse) }
|
405
|
-
else
|
406
|
-
|
407
|
-
return sql if binds.blank?
|
408
|
-
sql.gsub('?') { quote(*binds.shift.reverse) }
|
479
|
+
else
|
480
|
+
arel
|
409
481
|
end
|
410
482
|
end
|
411
483
|
|
412
484
|
else # AR-2.3 no #to_sql method
|
413
485
|
|
414
|
-
|
415
|
-
|
416
|
-
sql = sql.send(:to_sql) if sql.respond_to?(:to_sql)
|
417
|
-
return sql if binds.blank?
|
418
|
-
copy = binds.dup
|
419
|
-
sql.gsub('?') { quote(*copy.shift.reverse) }
|
486
|
+
def to_sql(sql, binds = nil)
|
487
|
+
sql
|
420
488
|
end
|
421
489
|
|
422
490
|
end
|
@@ -467,18 +535,28 @@ module ActiveRecord
|
|
467
535
|
|
468
536
|
private
|
469
537
|
|
470
|
-
|
471
|
-
|
472
|
-
|
473
|
-
|
474
|
-
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
538
|
+
def prepared_statements?
|
539
|
+
self.class.prepared_statements?(config)
|
540
|
+
end
|
541
|
+
|
542
|
+
def self.prepared_statements?(config)
|
543
|
+
config.key?(:prepared_statements) ?
|
544
|
+
type_cast_config_to_boolean(config.fetch(:prepared_statements)) :
|
545
|
+
false # NOTE: off by default for now
|
546
|
+
end
|
547
|
+
|
548
|
+
def suble_binds(sql, binds)
|
549
|
+
return sql if binds.nil? || binds.empty?
|
550
|
+
copy = binds.dup
|
551
|
+
sql.gsub('?') { quote(*copy.shift.reverse) }
|
552
|
+
end
|
553
|
+
|
554
|
+
# @deprecated replaced with {#suble_binds}
|
555
|
+
def substitute_binds(sql, binds)
|
556
|
+
suble_binds(extract_sql(sql), binds)
|
479
557
|
end
|
480
558
|
|
481
|
-
#
|
559
|
+
# @deprecated no longer used
|
482
560
|
def extract_sql(obj)
|
483
561
|
obj.respond_to?(:to_sql) ? obj.send(:to_sql) : obj
|
484
562
|
end
|